HDU 1385 Minimum Transport Cost (输出字典序最小路径)【最短路】

<题目链接>

题目大意:
给你一张图,有n个点,每个点都有需要缴的税,两个直接相连点之间的道路也有需要花费的费用。现在进行多次询问,给定起点和终点,输出给定起点和终点之间最少花费是多少,并且输出最少花费所走的路径,如果有多条路径花费最少,则输出字典序最小的那条。

解题分析:

输出最短路的路径问题,需要注意的是,题目要求输出的最短路径的字典序最小,所以我们在每次松弛的时候,都需要加上判断。如果有多个点的最短路相同,则用DFS求出它们之前走过的路径,并且进行比较,然后选字典序最小的那条。

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 #define clr(a,b) memset(a,b,sizeof(a))
 8 #define rep(i,s,t) for(int i=s;i<=t;i++)
 9 #define INF 0x3f3f3f3f
10 const int M = 100+10;
11 int n,pos;
12 int path[M],mp[M][M],tax[M],vis[M],dis[M]; 
13 char s1[110],s2[110];
14 void dfs(int cur,char *s){     //找到这个点之前记录的路径s
15     if(cur == -1)return;  
16     dfs(path[cur],s);  
17     s[pos++]=cur+'0';  
18 }  
19 bool Compare(int re,int now)  {  
20     pos=0;dfs(re,s1);s1[pos] = '0';   //将起点到re的最短路径储存 
21     pos=0;dfs(now,s2);s2[pos++]=re+'0';s2[pos]=0; //将起点到u的最短路径储存
22     if(strcmp(s1,s2)>0)return true;   //比较两个最短路之间的大小
23     return false;  
24 } 
25 void Dij(int st,int ed){
26     rep(i,1,n){
27         dis[i]=mp[st][i]+tax[i];     //将与st直接相连的点,边权与点权相加,视为经过i号城市的代价   
28         if(i==st)continue;    
29         if(dis[i]<INF)path[i]=st;    //初始化path 
30     }
31     rep(i,1,n){
32         int mn=INF,cur;
33         rep(j,1,n) if(dis[j] < mn && !vis[j]) {     //找到每一轮的起始节点
34                 mn=dis[j],cur=j;
35         }vis[cur]=1;
36         rep(k,1,n) if(mp[cur][k] < INF){
37             if(dis[k]>dis[cur]+mp[cur][k]+tax[k]){   //进行松弛,并且记录上一个节点
38                 dis[k]=dis[cur]+mp[cur][k]+tax[k];
39                 path[k]=cur;
40             }else if(dis[k] == dis[cur]+mp[cur][k]+tax[k] && Compare(k,cur)){
41                 path[k]=cur;  
42             }//若有多条最短路径(最短距离相同的时候)进行字典序大小判断,注意不能只比较一个节点,需要比较整个路径
43         }
44     }
45 }
46 void show(int cur,int st){
47     if(cur == st){ cout<<cur; return ;}
48     show(path[cur],st);
49     cout<<"-->"<<cur;
50 }
51 int main(){
52     while(~scanf("%d",&n),n){
53         rep(i,1,n) rep(j,1,n){
54             scanf("%d",&mp[i][j]);
55             if(mp[i][j]==-1)mp[i][j]=INF;
56         }
57         rep(i,1,n)scanf("%d",&tax[i]);
58         int u,v;while(scanf("%d%d",&u,&v)){
59             if(u==-1 && v==-1)break;
60             clr(vis,0);clr(path,-1);
61             Dij(u,v);
62             cout<<"From "<<u<<" to "<<v<<" :"<<endl<<"Path: ";
63             show(v,u);puts("");   //从终点开始,利用递归,将逆序存储的路径正序输出
64             cout<<"Total cost : "<<dis[v]-tax[v]<<endl<<endl;     //减去终点城市的城市税
65         }
66     }
67 }

2018-12-06

猜你喜欢

转载自www.cnblogs.com/00isok/p/10076006.html