【省选模拟试题】排水系统 dijkstra+最短路径树+优先队列维护(当然这个和dij的不是同一个)

来源:互联网 发布:退休工资计算软件 编辑:程序博客网 时间:2024/04/29 08:31

【问题描述】

  波赛多尼城有着复杂而有效的排水系统,为城里的居民提供生活上的便利。准确地说,城里共有M条排水管道,连接着N座建筑。每条排水管连接两座不同的建筑,水可以在排水管道内任意流动。两座建筑之间最多有一条排水管连接。在这个排水网上有两个建筑非常重要:海神波塞冬神殿,以及一个惟一的出海口。

  城里的居民非常担心神殿的排水问题,因为那会触怒他们最尊敬的神明。他们决定修理他们的排水管道,但是却筹不到足够的材料。于是决定只加固这么一条水管,若这条水管完全阻塞,其他水管正常工作的时候,水从神殿到出海口的最短距离最长。输入数据保证任意一条水管阻塞时依然有从神殿到出海口的排水管道。

【输入格式】

  第1行包含两个正整数N(3<=N<=100000),M(1<=M<=200000)。
  以下M行,每行包含3个正整数u,v,len(0<=u,v < N,u!=v,1<=L<=1000),表示编号为u和编号为v的两座建筑由一条长度为 len的排水管道直接连接。建筑物是从0开始编号的,神殿的编号为0,出海口的编号为1。

【输出格式】

  一个整数,表示被维修的这条管道堵塞的时候水从神殿到出海口的最短距离。

【输入样例】

6 8
0 2 10
0 4 12
2 3 6
4 5 3
3 4 12
2 5 4
3 1 5
5 1 24

【输出样例】

38

【数据范围】

20%的数据满足:1<=N<=5000, 1<=M<=10000
60%的数据满足:1<=N<=10000, 1<=M<=50000
100%的数据满足:1<=N<=100000, 1<=M<=200000

————————————————————————————————————————————————————

这个。。。考试的时候只打了个暴力然后就35分滚粗。。。。

教练:只需要枚举最短路上的边,你们就有60分了啊!!怎么全都是35啊?
众人:我们就是枚举的最短路上的边啊。。。。(雾)
教练:你们用的dijkstra还是SPFA?
众人:dijkstra啊。。。。。
教练:诶我的暴力怎么有60分。。。。。

下面说说思路。

暴力:
我们可以枚举图中的每一条边去删除,然后跑dijkstra确定0->1的最短路径,更新答案。显然会TL,有一点点优化是枚举最短路上的边。但是显然还是不行。对于特殊的数据直接可以卡爆这样的算法(脑补一下0和1是一条链然后链上两个点之间隔一个点连一条边。。。)

优化:
显然我们需要枚举的范围最少只能是最短路上的边,感觉上是不可以缩小的了。那么需要挖掘一些性质来加速枚举每一条边得到解的过程。

首先我们可以得到一棵0为根的最短路径树和1为根的最短路径树。设0到任意点i的最短路表示为ds[i],1到任意点i的最短路表示为dt[i]。现在对0为根的树进行操作,删除一条边,可以发现树被分成了上下两个集合。显然0到上方集合中的任意一个点的最短路并没有发生变化,而1到下方集合中任意一个点的最短路也没有发生(在最短路径树中如果一个点j是另一个点i为根的子树中的一个点,那么这个时候两点之间在树上的距离就是它们之间在图中的最短距离,否则这个距离一定会缩短,j不在i为根的子树中的时候这两个点在树上的距离就和图上的最短距离没有什么关系了)。
那么也就是说如果这个时候有一条边跨越了两个集合,那么就形成了0->1的一条路径。设上方集合中的端点为u,下方集合中的端点为v,由于上下方集合中的ds[u]和dt[v]都满足最优性,所以这个时候我们只需要枚举每一条跨越集合的边,然后比较ds[u]+w(u,v)+dt[v],就可以找到此时0->1的最短路。

核心思想都交代在上面了,实现的话可以先生成0为根的最短路径树(实际上可以不用真的做出来看ds数组和vis数组就可以判断了),然后从1开始向上沿着fa爬,枚举删除这个点的父边。每爬一次下方集合中都会增加一些点,用遍历找到它们,然后扫描跨越集合的边,找到一条就把ds[u]+w(u,v)+dt[v]甩进优先队列里面,顺便把u也甩进去。从队顶弹出最小元素,如果发现这个元素中的u已经在下方集合中就舍弃,继续弹出,用合格的解来更新答案(我是动了一下下标的)。

时间复杂度O(mlogn+mlogm)

AC代码:

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<cmath>#include<queue>#include<set>#include<map>#include<vector>#include<cctype>#define inf 2e9+5using namespace std;const int maxn=100005;const int maxm=200005;int N,M;struct edge{ int to,next,w; }E[maxm<<1];int first[maxn],np,ds[maxn],dt[maxn];int fa[maxn],q[maxn],front,rear;struct data{ int id,v; };struct cmp{    bool operator () (data x,data y)    {        return x.v>y.v;    }};bool vis[maxn];int A[maxn],cnt;void _scanf(int &x){    x=0;    char ch=getchar();    while(ch<'0'||ch>'9') ch=getchar();    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();}void add_edge(int u,int v,int w){    E[++np]=(edge){v,first[u],w};    first[u]=np;}void data_in(){    _scanf(N);_scanf(M);    int x,y,z;    for(int i=1;i<=M;i++)    {        _scanf(x);_scanf(y);_scanf(z);        add_edge(x+1,y+1,z);        add_edge(y+1,x+1,z);    }}void dijkstra(int s,int *d){    for(int i=1;i<=N;i++) d[i]=inf;    priority_queue<data,vector<data>,cmp>pq;    d[s]=0;    fa[s]=0;    pq.push((data){s,0});    data tmp;    int i,j;    while(!pq.empty())    {        tmp=pq.top(); pq.pop();        i=tmp.id;        if(d[i]<tmp.v) continue;        for(int p=first[i];p;p=E[p].next)        {            j=E[p].to;            if(d[i]+E[p].w<d[j])            {                d[j]=d[i]+E[p].w;                fa[j]=i;                pq.push((data){j,d[j]});            }        }    }}void work(){    dijkstra(2,dt);    dijkstra(1,ds);    priority_queue<data,vector<data>,cmp>pq;    int now=2,ans=0;    data tmp;    while(now!=1)    {        front=rear=0;        q[rear++]=now;        vis[now]=1;        while(front!=rear)        {            int i=q[front++];            for(int p=first[i];p;p=E[p].next)            {                int j=E[p].to;                if(!vis[j]&&j!=fa[i]&&i!=fa[j])                {                    pq.push((data){j,ds[j]+E[p].w+dt[i]});                }                if(ds[i]+E[p].w!=ds[j]) continue;                if(vis[j]) continue;                vis[j]=1;                q[rear++]=j;            }        }        while(!pq.empty()&&vis[pq.top().id]) pq.pop();        if(!pq.empty()) ans=max(ans,pq.top().v);        now=fa[now];    }    printf("%d\n",ans);}int main(){    freopen("test.in","r",stdin);    freopen("test.out","w",stdout);    data_in();    work();    return 0;}
阅读全文
0 0