题目链接:http://vjudge.net/contest/143062#problem/C
题意:
给定一个无向图,大写字母是城市,小写字母是村庄,经过城市交过路费为当前货物的%5,路过村庄固定交1,给定起点终点和到目标地点要剩下的货物,问最少要带多少货物上路,并输出路径,如果有多种方案,要求字典序最小.
分析:
逆向最短路: 因为要求的就是起点的货量,从终点出发求最短路,但是,费用的计算要处理,重新定义d 数组,d[i] 表示,进入节点 I 以后,还要多少 d[i] 个 货品 才能到达终点。d[T] = P;
然后就是怎么求 d[i] 了,根据 i 的类型, i >=26 ,就需要 d[i] + 1;
否则就是 20 里面抽 1;
#include <bits/stdc++.h> using namespace std; const int maxn = 52 + 10; const long long INF = 1LL << 60; int n; int G[maxn][maxn]; bool mark[maxn]; int p; int src; int dest; long long d[maxn]; int read_node() { char ch[9]; scanf("%s", ch); if(ch[0] >= 'A' && ch[0] <= 'Z') return ch[0] - 'A'; else return ch[0] - 'a' + 26; } char format_node(int u) { return u < 26 ? 'A' + u : 'a' + (u - 26); } // 拿着item个东西去结点next,还剩多少个东西 long long forward(long long item, int next) { if(next < 26) return item - (item + 19) / 20; return item - 1; } // 至少要拿着多少个东西到达结点u,交税以后还能剩d[u]个东西 long long back(int u) { if(u >= 26) return d[u]+1; long long X = d[u] * 20 / 19; // 初始值 while(forward(X, u) < d[u]) X++; // 调整 return X; } void solve() { n = 52; // 总是有52个结点 memset(mark, 0, sizeof(mark)); d[dest] = p; mark[dest] = 1; for(int i = 0; i < n; i++) if(i != dest) { d[i] = INF; if(G[i][dest]) d[i] = back(dest); } // Dijkstra主过程,逆推 while(!mark[src]) { // 找最小的d int minu = -1; for(int i = 0; i < n; i++) if(!mark[i]) { if(minu < 0 || d[i] < d[minu]) minu = i; } mark[minu] = 1; // 更新其他结点的d for(int i = 0; i < n; i++) if(!mark[i]) { if(G[i][minu]) d[i] = min(d[i], back(minu)); } } printf("%lld\n", d[src]); printf("%c", format_node(src)); int u = src; long long item = d[src]; while(u != dest) { int next; for(next = 0; next < n; next++) // 找到第一个可以走的结点 if(G[u][next] && forward(item, next) >= d[next]) break; item = d[next]; printf("-%c", format_node(next)); u = next; } printf("\n"); } int main() { int kase = 0; while(scanf("%d", &n) == 1 && n >= 0) { memset(G, 0, sizeof(G)); for(int i = 0; i < n; i++) { int u = read_node(); int v = read_node(); if(u != v) G[u][v] = G[v][u] = 1; } scanf("%d", &p); src = read_node(); dest = read_node(); printf("Case %d:\n", ++kase); solve(); } return 0; }