题意:给出一个图的邻接矩阵,即任意两点之间的边权,再给出给个点的权值。再询问两个点之间的最短路(路径上除了始点和终点之外的点权+边权),并输出最短路路径,若有多条最短路,输出字典序小的。
解法:
主体还是Floyd,关于点权的处理,更新时的条件变为:f[i][j]=min(f[i][k]+f[k][j]+d[k])。
关于路径的记录,用path[i][j]表示从点i到点j的最短路上,从i点出发后到达的第一个点是哪个点。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define N 512
int n;
int f[N][N],tax[N],path[N][N];
int min(int x,int y)
{
return x<y?x:y;
}
void Init()
{
int i,j,d;
memset(f,0X3F,sizeof(f));
for(i=0;i<=n;i++) f[i][i]=0;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
scanf("%d",&d);
if(d!=-1) f[i][j]=d;
path[i][j]=j;//路径记录的初始化
}
for(i=1;i<=n;i++) scanf("%d",&tax[i]);
}
void Floyd()
{
int i,j,k,d;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
//右侧表达式中加上了经过点的权值
d=f[i][k]+f[k][j]+tax[k];
if(d<f[i][j])
{
//根据距离大小判断是否要更新
f[i][j]=d;
path[i][j]=path[i][k];
}
else if(d==f[i][j])
{
//根据字典序判断是否要更新路径
path[i][j]=min(path[i][j],path[i][k]);
}
}
}
void Output()
{
int i,j,k,x,y;
while(scanf("%d%d",&x,&y),!(x==-1 && y==-1))
{
k=x; j=y;
printf("From %d to %d :\n",k,j);
printf("Path: %d", k);
while(k!=j)
{
//依次输出路径直到到达终点
printf("-->%d",path[k][j]);
k=path[k][j];
}
printf("\n");
printf("Total cost : %d\n\n", f[x][y]);
}
}
int main()
{
while(scanf("%d",&n),n)
{
Init();
Floyd();
Output();
}
return 0;
}