Minimum Transport Cost HDU - 1385
考察:Floyd+输出路径
错误思路:
跑一遍Floyd,记录使g[i][j]>g[i][k]+g[k][j]+w[k] 变小的k.分为[l,k] [k,r]输出路径.
当g[i][j] = g[i][k]+g[k][j]+w[k],比较path[i][j] 与当前枚举点k的大小.
错误原因:
这个思路错在哪呢?当正解答案与其他路径长度相等时就容易WA.
比如这组数据:
5 0 2 4 -1 -1 -1 0 -1 -1 2 -1 -1 0 2 -1 -1 -1 -1 0 -1 -1 -1 -1 2 0 1 3 8 4 5 1 4
-1 -1
0
正解是1->2->5->4 错误程序会输出1 3 4
实际是当k = 5时,path[1][4]记录的是[3],我们用k与3比较当然是3比较小.这是因为path中断点在路径不同位置造成的.
思路:
Floyd预处理是正确的,但是难点在字典序上.按照思路我们应该从路径的第二个点开始比较,直到路径终点,也就是当g[i][j]被更新时,path[i][j]到底应该赋什么值?
对于每一个区间[i,j]都比较路径第二个点的大小,那么最后扩展的区间一定是字典序最小的.
1 #include <iostream> 2 #include <cstring> 3 #include <vector> 4 using namespace std; 5 typedef long long LL; 6 const int N = 310,INF = 0x3f3f3f3f; 7 int n,g[N][N],w[N],path[N][N],S,E; 8 vector<int> p; 9 void floyd() 10 { 11 for(int k=1;k<=n;k++) 12 for(int i=1;i<=n;i++) 13 for(int j=1;j<=n;j++) 14 { 15 if(g[i][k]==INF||g[k][j]==INF) continue; 16 int idx = path[i][k]; 17 if(i==k) idx = j; 18 if(g[i][j]>g[i][k]+g[k][j]+w[k]) 19 { 20 g[i][j] = g[i][k]+g[k][j]+w[k]; 21 path[i][j] = idx; 22 }else if(g[i][j]==g[i][k]+g[k][j]+w[k]&&path[i][j]>idx) path[i][j] = idx; 23 } 24 } 25 void dfs(int l,int r) 26 { 27 int k = path[l][r]; 28 if(k==r) return; 29 p.push_back(k); 30 dfs(k,r); 31 } 32 void Myprintf(int i,int j) 33 { 34 p.clear(); 35 p.push_back(i); 36 dfs(i,j); 37 if(i!=j) p.push_back(j); 38 } 39 int main() 40 { 41 while(scanf("%d",&n)!=EOF&&n) 42 { 43 44 for(int i=1;i<=n;i++) 45 for(int j=1;j<=n;j++) 46 { 47 scanf("%d",&g[i][j]); 48 if(g[i][j]==-1) g[i][j] = INF; 49 path[i][j] = j; 50 } 51 for(int i=1;i<=n;i++) scanf("%d",&w[i]); 52 floyd(); 53 while(scanf("%d%d",&S,&E)!=EOF&&S!=-1&&E!=-1) 54 { 55 if(g[S][E]==INF) continue; 56 printf("From %d to %d :\n",S,E); 57 printf("Path: "); 58 if(S!=E) 59 { 60 Myprintf(S,E); 61 for(int i=0;i<p.size()-1;i++) 62 printf("%d-->",p[i]); 63 printf("%d\n",p.back()); 64 printf("Total cost : %d\n\n",g[S][E]); 65 }else printf("%d\nTotal cost : 0\n\n",S); 66 67 } 68 } 69 return 0; 70 }