痛苦流涕啊, WA多次才过, 看了网上一些思路才懂。
最小路径还是非常不熟悉。
这题主要是边的权 和 顶点权的最小路径。
此题原意是求 两点间 边的权 + 顶点权 最小值路径 已经路径。
之前看书的就是递归方法找到路径。 、
网上更多是循环方式找到。
觉得循环方式比较容易懂。
做这题, 首先是floyd 所有点, 但是在floyd中有所改变。
将平时的
for(k=1; k<=N; k++) { for(i=1; i<=N; i++) { if(i==k || a[i][k]==-1) continue; for(j=1; j<=N; j++) { if(a[k][j]==-1 || i==k || j==k) continue; fee = a[i][k]+a[k][j] if(a[i][j]==-1 || a[i][j] > fee) { a[i][j] = fee; nex[i][j] = nex[i][k]; } } } }
改为
for(k=1; k<=N; k++) { for(i=1; i<=N; i++) { if(i==k || a[i][k]==-1) continue; for(j=1; j<=N; j++) { if(a[k][j]==-1 || i==k || j==k) continue; fee = a[i][k]+a[k][j]+b[k]; //加上点得权值b[k]。 if(a[i][j]==-1 || a[i][j] > fee) { a[i][j] = fee; nex[i][j] = nex[i][k]; } else if(a[i][j] == fee) //当权值相等是, 按字典序列记录边集合 { if(nex[i][j]>nex[i][k]) nex[i][j] = nex[i][k]; } } } }
一下是我的代码, 虽然是一道比较简单的题目, 由于不熟练, 做起来吃力。
#include <iostream> #include <fstream> using namespace std; int const MAX=100000, Max=1001; int a[Max][Max], b[Max], nex[Max][Max]; int N, len; void floyd() { int i, j, k, fee; for(i=1; i<=N; i++) for(j=1; j<=N; j++) nex[i][j] = j; for(k=1; k<=N; k++) { for(i=1; i<=N; i++) { if(i==k || a[i][k]==-1) continue; for(j=1; j<=N; j++) { if(a[k][j]==-1 || i==k || j==k) continue; fee = a[i][k]+a[k][j]+b[k]; if(a[i][j]==-1 || a[i][j] > fee) { a[i][j] = fee; nex[i][j] = nex[i][k]; } else if(a[i][j] == fee) { if(nex[i][j]>nex[i][k]) nex[i][j] = nex[i][k]; } } } } } void path(int i, int j) { if(j == nex[i][j]) { printf("%d-->%d\n", i, j); } else { printf("%d-->", i); path(nex[i][j], j); } } int main() { //ifstream in("OpenJudgeText.txt"); int i, j; int A, B; while(cin>>N && N) { for(i=1; i<=N; i++) for(j=1; j<=N; j++) a[i][j] = MAX; memset(b, 0, sizeof b); for(i=1; i<=N; i++) for(j=1; j<=N; j++) cin>>a[i][j]; for(i=1; i<=N; i++) cin>>b[i]; floyd(); while(cin>>A>>B && (A!=-1 || B!=-1)) { printf("From %d to %d :\n", A, B); if(A == B) //注意A==B时, 路劲就一个数字。 printf("Path: %d\n", A); else { printf("Path: "); path(A, B); } printf("Total cost : %d\n\n", a[A][B]); } } return 0; }