题目大意:
告诉你n条边构成的村庄和城镇构成的图,每到达一个村庄减少1个单位的货物,到达一个城镇要减少
[(wi+19)/20]
个货物,问到达终点时要有p个货物,从起点起应至少携带多少货物,并求字典序最小的的路径。
分析:
我们可以从终点出发,计算到起点时的最短路径,这样起点的距离就代表了从起点出发需要的货物数量,则我们的主要任务就是求出字典序最小的路径。这很好解决,根据最短路树的处理可以直接在求解最短路的过程中解决。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 60;
const long long inf = 1LL << 60;
struct edge { int from, to; };
struct Heapnode {
long long d; int u;
bool operator < (const Heapnode& rhs) const {
return d > rhs.d;
}
};
struct Dijkstra {
int n, m;
vector<int> G[maxn];
vector<edge> edges;
int pre[maxn];
char village[maxn];
long long dis[maxn];
bool done[maxn], type[maxn];
long long cost(int u) {
if(type[u]) return dis[u] + 1;
else {
long long delta = dis[u] / 19 * 20;
while(delta-(delta + 19)/20 < dis[u]) delta++;
return delta;
}
}
void init(int n) {
this -> n = n;
for(int i=0; i<n; i++) G[i].clear();
edges.clear();
}
void add_edge(int from, int to) {
edges.push_back((edge){from, to});
m = edges.size();
G[from].push_back(m-1);
}
void dijkstra(int s) {
priority_queue<Heapnode> q;
for(int i=0; i<n; i++) if(i != s) dis[i] = inf;
memset(done, false, sizeof(done));
q.push((Heapnode){0, s});
while(!q.empty()) {
Heapnode x = q.top(); q.pop();
int u = x.u; if(done[u]) continue; done[u] = true;
for(int i=0; i<(int)G[u].size(); i++) {
edge& e = edges[G[u][i]];
if(dis[e.to] > cost(u)) {
dis[e.to] = cost(u);
pre[e.to] = G[u][i];
q.push((Heapnode){dis[e.to], e.to});
}else if(dis[e.to] == cost(u)) {
pre[e.to] = edges[pre[e.to]].from < u ? pre[e.to] : G[u][i];
}
}
}
}
}Dij;
char formatchar(int a) {
if(a > 25) return a - 26 + 'a';
else return a + 'A';
}
int idx(char ch) {
int id;
if(ch >= 'A' && ch <= 'Z') id = ch - 'A';
else id = ch - 'a' + 26;
Dij.type[id] = (ch >= 'a' && ch <= 'z');
return id;
}
char a[3], b[3];
int Case;
int m, u, v, p, s, t;
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt", "r", stdin);
freopen("ans.txt", "w", stdout);
#endif
while(scanf("%d", &m) == 1 && m>=0) {
Dij.init(maxn);
for(int i=0; i<m; i++) {
scanf("%s%s", a, b);
u = idx(a[0]); v = idx(b[0]);
Dij.add_edge(u, v);
Dij.add_edge(v, u);
}
scanf("%d", &p);
scanf("%s%s", a, b);
s = idx(a[0]); t = idx(b[0]);
Dij.dis[t] = p;
Dij.dijkstra(t);
printf("Case %d:\n", ++Case);
printf("%lld\n", Dij.dis[s]);
for(int i=s; ; i=Dij.edges[Dij.pre[i]].from) {
printf("%c%c", formatchar(i), i == t ? '\n' : '-');
if(i == t) break;
}
}
return 0;
}