參考c++
http://www.pianshen.com/article/5980255339/算法
(參考網站的代碼註釋中「大路加小路」與「小路加大路」反了,網站中對spfa算法的描述頗有參考價值)ide
思路網站
spfa+大路小路分開處理spa
實現code
經過Floyd算法得出純小路的點間最短路徑,經過dis[wide][i]存儲最後一條路爲大路時源點到i的最短路徑,dis[narrow][i]存儲最後一條路爲小路時源點到i的最短路徑,這樣spfa要考慮「大路加大路」「小路加大路」「大路加小路」三種狀況。blog
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 #define MAXN 505 6 7 typedef long long ll; 8 9 int n,m; 10 ll G[2][MAXN][MAXN]; 11 ll dis[2][MAXN]; 12 bool inque[MAXN]; 13 queue<int> q; 14 15 const ll inf=1e18; 16 const int wide=0; 17 const int narrow=1; 18 19 int spfa(int start,int n){ 20 //初始化 21 for(int i=1;i<=n;i++){ 22 dis[0][i]=dis[1][i]=inf; 23 inque[i]=false; 24 } 25 //start入隊 26 q.push(start); 27 inque[start]=true; 28 dis[wide][start]=dis[narrow][start]=0; 29 //spfa計算最短路徑 30 int u; 31 ll v; 32 while(!q.empty()){ 33 //出隊 34 u=q.front(); 35 q.pop(); 36 inque[u]=false; 37 38 for(int i=1;i<=n;i++){ 39 v=G[wide][u][i]; 40 //大路加大路 41 if(dis[wide][i]>dis[wide][u]+v){ 42 dis[wide][i]=dis[wide][u]+v; 43 if(!inque[i]){ 44 q.push(i); 45 inque[i]=true; 46 } 47 } 48 //小路加大路 49 if(dis[wide][i]>dis[narrow][u]+v){ 50 dis[wide][i]=dis[narrow][u]+v; 51 if(!inque[i]){ 52 q.push(i); 53 inque[i]=true; 54 } 55 } 56 //大路加小路 57 v=G[narrow][u][i]; 58 if(v!=inf&&dis[narrow][i]>dis[wide][u]+v*v){ 59 dis[narrow][i]=dis[wide][u]+v*v; 60 if(!inque[i]){ 61 q.push(i); 62 inque[i]=true; 63 } 64 } 65 } 66 } 67 return min(dis[wide][n],dis[narrow][n]); 68 } 69 70 int main(){ 71 cin>>n; 72 cin>>m; 73 //初始化 74 for(int i=1;i<=n;i++){ 75 for(int j=1;j<=n;j++){ 76 G[0][i][j]=G[1][i][j]=inf; 77 } 78 } 79 //輸入邊 80 int type,u,v,w; 81 for(int i=0;i<m;i++){ 82 cin>>type>>u>>v>>w; 83 if(G[type][u][v]>w){ //注意有重邊的狀況 84 G[type][u][v]=G[type][v][u]=w; 85 } 86 } 87 //Floyd算法獲得小邊連小邊的狀況 88 for(int i=1;i<=n;i++){ 89 for(int j=i+1;j<=n;j++){ 90 for(int k=1;k<=n;k++){ 91 if(k==i||k==j){ 92 continue; 93 } 94 if(G[narrow][i][j]>G[narrow][i][k]+G[narrow][k][j]){ 95 G[narrow][i][j]=G[narrow][j][i]=G[narrow][i][k]+G[narrow][k][j]; 96 } 97 } 98 } 99 } 100 101 cout<<spfa(1,n); 102 103 return 0; 104 }
注意ci
有重複邊輸入的狀況,中間結果大小可能超過intget
題目it