【bzoj1726/Usaco2006 Nov】Roadblocks第二短路——SPFA
分析:题目要求一个连通图的从1到n的严格次短路,我们只需要在跑最短路的时候顺便判一下次短路是否能够被更新即可。
dis[x][0]表示1到x的最短路,而dis[x][1]则表示次短路,需要分成三类讨论:
dis[x][0]+e[i].w<dis[to][0],此时dis[x][1]是原最短路和dis[x][1]+e[i].w的较小值(注意这里最短路要在更新完次短路后再更新);
dis[x][0]+e[i].w>dis[to][0]&&dis[x][0]+e[i].w<dis[to][1],这条路虽然不能更新最短路,但可以更新次短路;
dis[x][0]+e[i].w==dis[to][0],因为是严格小于,所以不能把这个值赋给次短路,应为dis[to][1]=min(dis[to][1],dis[x][1]+w[i].w)。
另外,若这条边可以更新最短路或是次短路并且to不在队列中,再将to加入队列中。
最最后,记得每次一个点出队后要记得把标记清为0!!!
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 const int N=5005,inf=0x3f3f3f3f; 6 int n,m,tot=0,first[N],q[N]; 7 struct node{ 8 int ne,to,w; 9 }e[100000*2]; 10 int read(){ 11 int ans=0,f=1;char c=getchar(); 12 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 13 while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();} 14 return ans*f; 15 } 16 int dis[N][2]; 17 bool ok[N]; 18 void add(int u,int v,int z){ 19 tot++;e[tot].ne=first[u];first[u]=tot;e[tot].to=v;e[tot].w=z; 20 tot++;e[tot].ne=first[v];first[v]=tot;e[tot].to=u;e[tot].w=z; 21 } 22 int mins(int x,int y){return x>y?y:x;} 23 void spfa(){ 24 for(int i=1;i<=n;i++)dis[i][1]=dis[i][0]=inf; 25 dis[1][0]=0; 26 int h=0,t=1;q[0]=1;ok[1]=1; 27 while(h!=t){ 28 int x=q[h++];if(h>=5000)h=0; 29 for(int i=first[x];i;i=e[i].ne){ 30 int to=e[i].to;bool ff=0; 31 int p1=dis[x][0]+e[i].w; 32 if(dis[to][0]>p1){ 33 ff=1;dis[to][1]=mins(dis[to][0],dis[x][1]+e[i].w); 34 dis[to][0]=p1; 35 } 36 else if(p1>dis[to][0]&&dis[to][1]>p1)ff=1,dis[to][1]=p1; 37 else if(dis[to][1]>dis[x][1]+e[i].w)ff=1,dis[to][1]=dis[x][1]+e[i].w; 38 if(!ok[to]&&ff){ 39 ok[to]=1;q[t++]=to;if(t>=5000)t=0; 40 } 41 } 42 ok[x]=0; 43 } 44 } 45 int main(){ 46 n=read();m=read(); 47 for(int i=1,a,b,c;i<=m;i++){ 48 a=read();b=read();c=read(); 49 add(a,b,c); 50 } 51 spfa(); 52 printf("%d",dis[n][1]); 53 return 0; 54 }