首页 > 其他分享 >删边最短路 思路

删边最短路 思路

时间:2024-01-28 16:44:41浏览次数:34  
标签:cnt 路上 int 短路 mid 思路 删边 dis

例题LuoguP2685 桥

题意就是给一张存在重边和自环的图,求出使得删去一条边后最短路长度最长的方案数。(当然不能删掉割边,不然直接嗝屁了)

分析

首先考虑删哪条边,和最短路相关的边就只有在最短路上和不在最短路上的边。
如果删掉的边不在最短路上,那么最短路长度不会变大,所以要删的边只能是最短路上的边。

然后我们需要知道一个性质,
我们可以在脑子里想出一个简单的图,1和n是两个端点,我们要在这个最短路上删去一条边,那么删去后的最短路一定满足只有一段不是原最短路上的;
简单的证明:如果有两段不是原最短路上的,直接把其中一段改成最短路上的显然更优。

接下来的思考有两个方向,一个是枚举最短路上的边删除,再跑最短路,复杂度必然是轰轰烈烈的\({O(L*nlogn)}\),随便爆炸的。

另一个方向是枚举所有非最短路上的边,如果删除某条边后的最短路经过这条边,最短路长度是多少。简单这样思考必然还是复杂度大爆炸的;
考虑到删除最短路上某一条边时,新的最短路一定是只和部分非原最短路上的边相关的,那么反过来思考也就是说部分非原最短路上的边一定是会影响到新最短路的。

这样子考虑,枚举非原最短路上的边,假设新的最短路经过这条边,那么一定会在原最短路上有一段连续的边满足:删去这条边后的新最短路一定经过枚举的非原最短路的边。
现在要找到这样一段连续的边,我们以其中一个端点为源点bfs,从枚举的边的靠近源点的这个点出发,不断向父节点走直到走到最短路上,此时最短路上的这个点就是我们需要找到的这一段的一个端点,另一边同理即可。

也就是说对于每条非原最短路上的边,可以对最短路上一个一段连续的边的答案产生影响,题中所求为最短路,所以可以用线段树维护区间最小值,最后统计整个区间的最大值即可。

因为线段树只需要维护最小值,所以线段树区间修改的时候只需要简单的打上标记即可,最后一次性下传标记。

代码

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL),cout.tie(NULL)
const int N = 1e3 + 5, M = 1e6 + 5, inf = 0x3f3f3f3f;
struct Edge{
    int to, next, val;
}e[M << 1];
int head[N], tot;
inline void add(int u, int v, int w){
    e[++tot].to = v, e[tot].next = head[u], e[tot].val = w;
    head[u] = tot;
}
int n, m, cnt;
int dis1[N], dis2[N], sway[N], id[N], lm[N], rm[N], ans[N];
bool vis[N], in[M << 1];
struct SegmentTree{
    #define ls(i) i << 1
    #define rs(i) (i << 1) + 1
    int minn[N << 2];
    void build(int i, int l, int r){
        minn[i] = inf;
        if (l == r) return;
        int mid = l + (r - l >> 1);
        build(ls(i), l, mid);
        build(rs(i), mid + 1, r);
    }
    void modify(int i, int l, int r, int o, int s, int c){
        if (o <= l && r <= s){
            minn[i] = min(minn[i], c);
            return;
        }
        int mid = l + (r - l >> 1);
        if (mid >= o) modify(ls(i), l, mid, o, s, c);
        if (mid <  s) modify(rs(i), mid + 1, r, o, s, c);
    }
    void pushdown(int i, int l, int r){
        if (l == r){
            ans[l] = minn[i];
            return;
        }   
        minn[ls(i)] = min(minn[ls(i)], minn[i]), minn[rs(i)] = min( minn[rs(i)], minn[i] );
        int mid = l + (r - l >> 1);
        pushdown(ls(i), l, mid);
        pushdown(rs(i), mid + 1, r);
    }
}T;
void dijkstra(int *dis, int s){
    for (int i(1); i <= n; ++i) dis[i] = inf, vis[i] = false;
    dis[s] = 0;
    priority_queue<pair<int, int> > q;
    q.push({0, s});
    while (!q.empty()){
        int u = q.top().second; q.pop();
        if (vis[u]) continue;
        vis[u] = true;
        for (int i(head[u]); i; i = e[i].next){
            int v = e[i].to;
            if (vis[v]) continue;
            if (dis[u] + e[i].val < dis[v]){
                dis[v] = dis[u] + e[i].val;
                q.push({-dis[v], v});
            }
        }
    }
}

void getlink(){
    int u = 1;
    while (u != n){
        sway[++cnt] = u;
        id[u] = cnt;
        for (int i(head[u]); i; i = e[i].next){
            int v = e[i].to;
            if (dis2[u] == dis2[v] + e[i].val){
                in[i] = true;
                u = v;
                break;
            }
        }
    }
    sway[++cnt] = n;
    id[n] = cnt;
}

void bfs(int u, int *dis, int *a){
    queue<int> q;
    q.push(sway[u]);
    a[sway[u]] = u;
    while(!q.empty()){
        int x = q.front(); q.pop();
        for (int i(head[x]); i; i = e[i].next){
            int v = e[i].to;
            if (!id[v] && !a[v] && dis[x] + e[i].val == dis[v]){
                a[v] = u;
                q.push(v);
            }
        }
    }
}

void doit(){
    cin >> n >> m;
    for (int i(1), x, y, z; i <= m; ++i){
        cin >> x >> y >> z;
        add(x, y, z), add(y, x, z);
    }
    dijkstra(dis2, n);
    dijkstra(dis1, 1);

    getlink();

    for (int i(1); i <= cnt; ++i) bfs(i, dis1, lm);
    for (int i(cnt); i >= 1; --i) bfs(i, dis2, rm);

    T.build(1, 1, cnt);
    for (int u(1); u <= n; ++u)
        for (int i(head[u]); i; i = e[i].next){
            if (in[i]) continue;
            int v = e[i].to;
            if (lm[u] > 0 && rm[v] > 0 && lm[u] < rm[v]) T.modify(1, 1, cnt, lm[u], rm[v] - 1, dis1[u] + e[i].val + dis2[v]); 
        }
    T.pushdown(1, 1, cnt);
    int fans = 0, fcnt = 0;
    for (int i(1); i < cnt; ++i){
        if (ans[i] > fans){
            fans = ans[i];
            fcnt = 1;
        }
        else if (ans[i] == fans) ++fcnt;
    }
    if (fans == dis1[n]) fcnt = m;
    cout << fans << " " << fcnt;
    //  for (int i(1); i < cnt; ++i){
    //     if (ans[i] > fans)
    //         fans = ans[i];
    //  }
    // cout << fans;
}

int main(){
    IOS;
    //freopen("in.txt", "r", stdin);
    int T = 1;
    while (T--){
        doit();
    }
    return 0;
}

标签:cnt,路上,int,短路,mid,思路,删边,dis
From: https://www.cnblogs.com/ancer/p/17992959

相关文章

  • 单源最短路径算法之bellman-ford
    单源最短路径算法之\(bellman-ford\)以边为研究对象单起点多终允许有负边权\(bellman-ford\)的工作原理假设\(n\)个点\(m\)条有向边的图,求\(s\)为起点的最短路条以\(s\)出发的最短路,最多包含\(n\)个点,\(n-1\)条边对于一条边\((x,y,w)\),\(y\)可能被\(x\)......
  • 头像和消息组件css实现思路
    修改后:实现代码(可以用于组装头像和消息):<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>D......
  • 我们前端同学最该关注什么-附评分思路
    来点实际的吧说一下我的想法(吐槽),我们是否对过程太过痴迷,忘记了我们要什么?文末给出我认为的好的标准比如:大家仿佛都在看框架、工具包和开发过程中的内容,这点可能是因为工期紧张,留给前端开发的时间不够,但996已经常态化的情况下,我们是不是该审查一下我们的结果:页面是否秒开?页面报错多......
  • 有边数限制的最短路
    第3题   有边数限制的最短路查看测评数据信息给定一个n个点m条边的有向图,图中可能存在重边和自环,边权可能为负数。请你求出从1号点到n号点的最多经过k条边的最短距离,如果无法从1号点走到n号点,输出impossible。注意:图中可能存在负权回路。1≤n,k≤500,1......
  • 学生们,就业思路打开,宇宙的尽头是……
    本文首发自公粽hao「林行学长」,欢迎来撩,免费领取20个求职工具资源包。了解校招、分享校招知识的学长来了!之前有人称文科的就业归宿的服务员,今天学长又看到网红把就业思路打开了:就业的尽头是销售!世界就是一个巨大的贩卖市场,有理有据!为了学校”居高不下“的就业率,大家也很努力地打开......
  • MSE/Istio 全链路灰度的挑战、实现思路与解决方案
    微服务架构下的灰度发布挑战在传统的单体应用架构中,灰度发布相对简单。只需要在服务的流量入口处进行分流,通过使用K8sService或各种类型的网关即可实现。然而,微服务架构引入了新的复杂性,服务之间的依赖关系错综复杂。有时候,某个功能的发布可能依赖于多个服务,要求灰度流量在整......
  • dijkstra算法(单源最短路径)
    单源最短路径是求解给定一个起点到其他所有的点的最短距离。适用的范围:有向图、边的权值没有负数洛谷测试链接代码实现#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>#include<string.h>#include<math.h>#include<time.h>#include<stdboo......
  • MAT使用思路总结
    参考:https://blog.csdn.net/x275920/article/details/123991656主要分为2种操作。简单粗暴来个内存泄漏分析LeakSuspects和TopConsumers,可以看出大部分简单的内存泄漏问题看保留堆/深堆RetainedHeap大的,这个表示如果这个对象被清理,那么RetainedHeap都是可以被清理的,所......
  • 图的最短路-Dijkstra 详解
    Dijkstra  概念注意一下,Dijkstra不适用于有负边权的图   就是刚开始一些点(集合B),把排序的结果放入集合A,先确定起点0,然后找集合B里面的最小值,这样才可以确定你修改的这个点的最短路在目前是最优解(后期可能改动),因为集合A的都是确定好了的最短路,所以集合A的数不做修......
  • 一种快速开发适配鸿蒙的App思路:基于小程序技术
    今年,在中国,被各大媒体和开发者称为“鸿蒙元年”。 在2023年底就有业内人士透露,华为明年将推出不兼容安卓的鸿蒙版本,未来IOS、鸿蒙、安卓将成为三个各自独立的系统。 果不其然,执行力超强的华为,与2024年1月18日的开发者(HDC)大会上,就官宣了“纯血鸿蒙”操作系统即将于2024......