题意:给一个无向图,要从起点s运送一批货物到达终点e,每个点代表城镇/乡村,经过城镇需要留下(num+19)/20的货物,而经过乡村只需要1货物即可。现在如果要让p货物到达e,那么从起点出发最少要准备多少货物?输出答案和路径(多条路径则必须输出字典序最小的)。注:终点需要花费,而起点不需要。
思路:这最短路变形的不错。要逆推过来求最短路径,那么就从e出发到s的距离!只是p比较大,而且城镇还得推出前一站到底需要多少货物,既然直接计算那么麻烦,也可以一直p++直到能留下p为止就推出来了;而乡村就容易推了,只是+1。但是还有个字典序要解决,则在碰到dist[u]==dist[v]+距离的时候就比较一下字典序谁小就记谁。
有一点别忘了,这是在逆推!!所以你要用出发点去更新终点时,要以出发点的dist来比较字典序。无向边是要建两条有向的,防止重边。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <bits/stdc++.h> 2 #define LL long long 3 #define pii pair<int,int> 4 #define INF 0x7f7f7f7f 5 using namespace std; 6 const int N=200; 7 int n, m, l, edge_cnt; 8 LL p; 9 vector<int> vect[N]; 10 struct node 11 { 12 int from, to; 13 node(){}; 14 node(int from,int to):from(from),to(to){}; 15 }edge[100000]; 16 17 void add_node(int from,int to) 18 { 19 edge[edge_cnt]=node(from, to); 20 vect[from].push_back(edge_cnt++); 21 } 22 23 LL dist[N]; 24 int path[N], vis[N]; 25 LL dijkstra(int s,int e) 26 { 27 memset(path, 0, sizeof(path)); 28 memset(vis, 0, sizeof(vis)); 29 memset(dist, 0x7f, sizeof(dist)); 30 31 priority_queue<pii,vector<pii>,greater<pii> > que; 32 que.push(make_pair(p,s)); 33 dist[s]=p; 34 35 while(!que.empty()) 36 { 37 int x=que.top().second;que.pop(); 38 if(vis[x]) continue; 39 vis[x]=1; 40 41 bool flag=isupper(x); //大写,花费多的 42 LL t=dist[x]+(dist[x]+19)/20; 43 while(t-(t+19)/20<dist[x]) t++; //注意不要超时 44 45 for(int i=0; i<vect[x].size(); i++) 46 { 47 node e=edge[vect[x][i]]; 48 if( flag ) 49 { 50 if(dist[e.to]>=t) 51 { 52 if(dist[e.to]==t) 53 { 54 if( x<edge[path[e.to]].from ) path[e.to]=vect[x][i]; //字典序 55 } 56 else path[e.to]=vect[x][i]; 57 58 dist[e.to]=t; 59 que.push(make_pair(dist[e.to],e.to)); 60 } 61 } 62 else 63 { 64 if(dist[e.to]>=dist[x]+1) 65 { 66 if(dist[e.to]==dist[x]+1) 67 { 68 if( x<edge[path[e.to]].from ) path[e.to]=vect[x][i]; //字典序 69 } 70 else path[e.to]=vect[x][i]; 71 72 dist[e.to]=dist[x]+1; 73 que.push(make_pair(dist[e.to],e.to)); 74 } 75 } 76 } 77 } 78 return dist[e]; 79 } 80 81 82 void cal(int s,int e) 83 { 84 cout<<dijkstra(s,e)<<endl; 85 vector<char> ans; 86 int ed=e; 87 while(ed!=s) 88 { 89 ans.push_back( ed ); 90 int t=path[ed]; 91 ed=edge[t].from; 92 } 93 ans.push_back(s); 94 printf("%c",ans[0]); 95 for(int i=1; i<ans.size(); i++) printf("-%c",ans[i]); 96 cout<<endl; 97 } 98 99 100 int main() 101 { 102 freopen("input.txt", "r", stdin); 103 char a, b; 104 int j=0; 105 while(scanf("%d", &n), n>=0) 106 { 107 edge_cnt=0; 108 memset(edge,0,sizeof(edge)); 109 for(int i=0; i<N; i++) vect[i].clear(); 110 int up=0; 111 for(int i=0; i<n; i++) 112 { 113 getchar(); 114 scanf("%c %c",&a,&b); //%c会接收到换行!! 115 add_node(a, b); 116 add_node(b, a); 117 } 118 scanf("%lld %c %c",&p, &a, &b); 119 printf("Case %d:\n",++j); 120 cal(b, a); 121 } 122 return 0; 123 }