最短路

来源:互联网 发布:安卓 ping软件 编辑:程序博客网 时间:2024/06/07 20:18

题目:

经过努力,LCJ终于获得了一个带薪假期。他准备要在N个城市中挑选若干个进行旅游,其中有K个城市他是一定要去的。然而他英(qi)明(guai)的上司KID向他提出了一个要求,因为经费的问题,他的旅行路线必须是某两个城市之间的一条最短路。现在LCJ就要在这N个城市之间的道路找到这样一条路线:它是一条某两个城市之间的最短路,经过了K个特殊的城市,在满足条件的路线中,找到最短的一条。 

输入

第一行两个数N,M。表示有N座城市,M条边。 
接下来M行每行三个数xi,yi,vi,表示有一条长度为vi的双向路径连接对应的两座城市。 
接下来一个数K。 
接下来一行K个数,表示一定要经过的城市。 

输出

一个数,符合要求的最短最短路长度。 

样例输入

6 61 2 22 6 21 3 13 4 14 5 15 6 135 1 3

样例输出

3

对于30%的数据,1<=N<=10,1<=M<=20 

对于60%的数据,1<=N<=500,1<=M<=1000。 
对于100%的数据,1<=N<=100000,1<=M<=300000,1<=vi<=10000,1<=K<=N,保证有解。 


这道题看了下题解,不明觉厉,然后听了zyf大神自己yy的算法:

1.在需要走到的点(下文称要点)中取一个点P

2.以P做一遍单源最短路,找到离它最远的要点Q

3.再以Q做一遍单源最短路,找到离他最远的要点M,答案就是dist(Q,M)

证明:

对于原题要求的路径必须是两点之间的最短路,可以肯定,这两个点都是要点,对于点Q,明显是路径的一个起点,而M,就是另一个起点,题目有保证有解,所以答案就是dist(Q,M)


#include<cstdio>#include<cstring>#include<iostream>const int maxn=100010,maxm=600010;using namespace std;int tot=0;int pre[maxm],son[maxm],v[maxm];int now[maxn];inline void add(int a,int b,int c){pre[++tot]=now[a];now[a]=tot;son[tot]=b;v[tot]=c;}void cc(int a,int b,int c){add(a,b,c);add(b,a,c);}inline int getint(){    char ch=getchar(); int tmp=0;    while (ch<'0' || ch>'9') ch=getchar();    for (;ch<='9' && ch>='0';ch=getchar()) tmp=tmp*10+ch-'0';    return tmp;}int h[maxn];int f[maxn];bool b[maxn];void spfa(int x){int t=0,w=1;h[1]=x;memset(f,63,sizeof(f));memset(b,0,sizeof(b));b[x]=1;f[x]=0;while (t!=w){if (++t==maxn) t=1;for (int p=now[h[t]];p;p=pre[p])if (f[h[t]]+v[p]<f[son[p]]){f[son[p]]=f[h[t]]+v[p];if (!b[son[p]]){b[son[p]]=1;if (++w==maxn) w=1;h[w]=son[p];int tt=t+1;if (tt==maxn) tt=1;if (f[h[tt]]>f[h[w]]) swap(h[tt],h[w]);}}b[h[t]]=0;}}int ne[maxn];int main(){int n=getint();int m=getint();for (int i=1;i<=m;++i){int a=getint(),b=getint(),c=getint();cc(a,b,c);}int k=getint();for (int i=1;i<=k;++i)ne[i]=getint();spfa(ne[1]);int ptmp=ne[1],tmp=0;for (int i=1;i<=k;++i)if (f[ne[i]]>tmp){ptmp=ne[i];tmp=f[ne[i]];}spfa(ptmp);int ans=0;for (int i=1;i<=k;++i)ans=max(ans,f[ne[i]]);printf("%d\n",ans);return 0;}


原创粉丝点击