【题意】题意就是说过某个村庄时需要给一定的费用,且路上也是需要给钱的,问如何才能使从村庄A运送货物到B花的费用最少,且字典序最小。

【分析】典型的多维最短路,优先考虑费用的为题,再费用相同时再考虑字典序的问题,这里的字典序指的是经过的村庄的编号先后构成的一个序列。这样的话,状态就应该含有费用,路径两个信息(结构体),然后进行状态转移。

【路径记录】path【i】【j】代表从i到j不包含i,j的第一个顶点。
【核心】优先更新路径长度,其次是字典序。

【AC代码】

#include <stdio.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 102;
int G[maxn][maxn],path[maxn][maxn],cost[maxn];
int i,j,k,s,e,n;
void Floyd()
{
    for(k=1; k<=n; k++)
    {
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                int cur=G[i][k]+G[k][j]+cost[k];
                if(cur<G[i][j])G[i][j]=cur,path[i][j]=path[i][k];
                else if(cur==G[i][j]){
                    if(path[i][j]>path[i][k]){
                        path[i][j]=path[i][k];
                    }
                }
            }
        }
    }
}
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        int data;
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                scanf("%d",&data);
                if(data==-1)G[i][j]=INF;
                else        G[i][j]=data;
                path[i][j]=j;
            }
        }
        for(int i=1; i<=n; i++)scanf("%d",&cost[i]);
        Floyd();
        while(~scanf("%d%d",&s,&e))
        {
            if(s==-1&&e==-1)break;
            printf("From %d to %d :\n",s,e);
            printf("Path: %d",s);
            int temp=s;
            while(temp!=e)
            {
                temp = path[temp][e];
                printf("-->%d",temp);
            }
            printf("\nTotal cost : %d\n\n",G[s][e]);
        }
    }
    return 0;
}