这题题意很明确,就是求图的次短路,我用了一个非常奇葩的方法:伟大的分类讨论;
注意,以下说明均针对无向图
首先,图的次短路只有2种情况:
1)1次最短路+乱转(源点->最短路上离其他点最近的点->离它最近的点->返回这个点->终点)
2)直接次短路(依次屏蔽每一条边)
可以证明,无向图的次短路仅有这2种情况,如有错误,请读者在评论区指出
2的情况非常好做,仅需依次屏蔽每一条边(最短路上的)后求最短路就好了,1号情况可以邻接表打擂台去取最小值即可
请读者务必好好理解最短路路径记忆的方法,非常非常重要!!!
参考程序如下:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<queue> 5 using namespace std; 6 int n,m,x,y,z,v[200005],w[200005],nxt[200005],head[200005],cnt,dist[200005],pre[200005],edge[200005]; 7 int minn1,lesss,ans,minn2,minn3,ans1=21374404,ans2,ans3,minn4; 8 int path[100000],num; 9 bool vis[200005]; 10 void add(int a,int b,int c) 11 { 12 v[++cnt]=b; 13 w[cnt]=c; 14 nxt[cnt]=head[a]; 15 head[a]=cnt; 16 } 17 void spfa(int s) 18 { 19 memset(dist,20,sizeof(dist)); 20 queue<int>q; 21 q.push(s); 22 dist[s]=0; 23 vis[s]=1; 24 while(!q.empty()) 25 { 26 int c=q.front(); 27 q.pop(); 28 vis[c]=0; 29 for(int i=head[c];i;i=nxt[i]) 30 { 31 int y=v[i]; 32 if(dist[y]>dist[c]+w[i]) 33 { 34 pre[y]=i;edge[y]=c; 35 dist[y]=dist[c]+w[i]; 36 if(!vis[y]) 37 { 38 q.push(y); 39 vis[y]=1; 40 } 41 } 42 } 43 } 44 } 45 int main() 46 { 47 cin>>n>>m; 48 for(int i=1;i<=m;i++) 49 { 50 cin>>x>>y>>z; 51 add(x,y,z); 52 add(y,x,z); 53 } 54 spfa(1); 55 minn3=dist[n]*3; 56 int s=21370444; 57 for(int i=head[n];i;i=nxt[i]) 58 { 59 s=min(s,w[i]*2); 60 } 61 minn2=dist[n]*2+s; 62 s=21370444; 63 for(int i=head[1];i;i=nxt[i]) 64 { 65 s=min(s,w[i]*2); 66 } 67 minn4=dist[n]*2+s; 68 minn1=dist[n]; 69 int now=n; 70 while(now!=1) 71 { 72 path[++num]=pre[now]; 73 now=edge[now]; 74 } 75 for(int i=1;i<=num;i++) 76 { 77 int s=w[path[i]]; 78 w[path[i]]=99999999; 79 spfa(1); 80 lesss=dist[n]; 81 if(lesss!=minn1)ans1=min(ans1,lesss); 82 w[path[i]]=s; 83 } 84 ans=min(ans1,min(minn2,min(minn3,minn4))); 85 cout<<ans; 86 return 0; 87 }