求最短路的算法最有名的是Dijkstra。所以一般拿到题目第一反应就是使用Dijkstra算法。但是此题要求的好几对起点和终点的最短路径。所以用Floyd是最好的选择。因为其他三种最短路的算法都是单源的。
输出字典序最小的路径则需要修改模版。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N =110, INF=1000000; int Map[N][N], dist[N][N], pre[N][N], c[N]; //pre存贮i到j路径中j的前一点 int n; void floyd() { int i,j,k; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { dist[i][j]=Map[i][j]; pre[i][j]=j; } } for(k=1;k<=n;k++) for(i=1;i<=n;i++) for(j=1;j<=n;j++) { //if(dist[i][k]==INF||dist[k][j]==INF) continue; int d=dist[i][k]+dist[k][j]+c[k]; if(d<dist[i][j]) { dist[i][j]=d; pre[i][j]=pre[i][k]; } else if(d==dist[i][j]) { if(pre[i][j]>pre[i][k]) pre[i][j]=pre[i][k]; } } } int main() { //freopen("test.txt","r",stdin); int i,j,k,a,b; while(scanf("%d",&n)!=EOF) { if(!n) break; for(i=1;i<=n;i++) for(j=1;j<=n;j++) { scanf("%d",&Map[i][j]); if(Map[i][j]<0) Map[i][j]=INF; } for(i=1;i<=n;i++) scanf("%d",&c[i]); while(scanf("%d%d",&a,&b)) { if(a==-1&&b==-1) break; floyd(); printf("From %d to %d : ",a,b); printf("Path: %d",a); k=a; while(k!=b){printf("-->%d",pre[k][b]);k=pre[k][b];} printf(" "); printf("Total cost : %d ",dist[a][b]); printf(" "); } } return 0; }
下面是Floyd的模版。pre[][]记录的是前驱。上面的记录的是后继。
const int N =1010, INF=0x3f3f3f3f; int Map[N][N], dist[N][N], pre[N][N]; //pre存贮i到j路径中j的前一点 int n; void floyd() { int i,j,k; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { dist[i][j]=Map[i][j]; pre[i][j]=i; } } for(k=1;k<=n;k++) for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(dist[i][k]!=INF&&dist[k][j]!=INF&& dist[i][k]+dist[k][j]<dist[i][j]) { dist[i][j]=dist[i][k]+ dist[k][j]; pre[i][j]=pre[k][j]; } } void init() { for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) Map[i][j]=INF; }