参考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