从s到t,每次经过一个村庄要缴纳1个单位的货物,经过一个城镇时,每20个货物就要缴纳一个,求字典序最小的最少花费路径。
用最短路的思想来解。从终点跑最短路,对于边<u, v>的边权值,如果u是村庄,边权自然是1,当u是城镇时,边权是min{key | key - (key+19)/20=d[u]}。
求出最短路后,从起始点dfs,每次沿着满足最距离且字典序最小的边走就OK了~
#include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<fstream> #include<sstream> #include<string> #include<vector> #include<cstdio> #include<queue> #include<stack> #include<cmath> #include<map> #include<set> #define FF(i, a, b) for(int i=a; i<b; i++) #define FD(i, a, b) for(int i=a; i>=b; i--) #define REP(i, n) for(int i=0; i<n; i++) #define CLR(a, b) memset(a, b, sizeof(a)) #define debug puts("**debug**") #define PB push_back #define LL long long using namespace std; LL bin(LL k) //二分查找路过城镇前所需最少货物 { LL L=0, R=k*2+1, M, ans; while(L <= R) { M = (L + R) >> 1; LL tmp = M - (M + 19) / 20; if(tmp > k) R = M - 1; else if(tmp == k) ans = M, R = M - 1; else L = M + 1; } return ans; } const int maxn = 111; const LL INF = 10000000000; int n, m, s, t; string name, ans; struct heap { LL d; int u; bool operator<(const heap rhs) const { return d > rhs.d; } }; vector<int> G[maxn]; bool done[maxn]; LL d[maxn], P; map<char, int> id; inline void init() { REP(i, maxn) G[i].clear(); n = 0; name.clear(); ans.clear(); id.clear(); } int get(char c) { if(!id.count(c)) id[c] = n++, name.PB(c); return id[c]; } void dij(int s) { REP(i, n) d[i] = INF; d[s] = P; priority_queue<heap> q; q.push((heap){0, s}); CLR(done, 0); while(!q.empty()) { heap x = q.top(); q.pop(); int nc = G[x.u].size(), u = x.u; if(done[u]) continue; done[u] = 1; REP(i, nc) { int v = G[u][i]; LL tmp = d[u] + 1; if(isupper(name[u])) tmp = bin(d[u]);//边权 if(d[v] > tmp) { d[v] = tmp; q.push((heap){d[v], v}); } } } } void dfs(int u) { if(u == t) return ; char c = 'z'; int nc = G[u].size(); REP(i, nc) { int v = G[u][i]; LL tmp = d[u] - 1; if(isupper(name[v])) tmp = d[u] - (d[u] + 19) / 20; if(d[v] == tmp) if(name[v] <= c) c = name[v]; //走字典序最小的路径 } ans.PB(c); dfs(id[c]); } int main() { int kase = 1; while(scanf("%d", &m), m != -1) { init(); char a[2], b[2]; while(m--) { scanf("%s%s", a, b); int aa = get(a[0]), bb = get(b[0]); G[aa].PB(bb), G[bb].PB(aa); } scanf("%lld %s%s", &P, a, b); s = get(a[0]), t = get(b[0]); dij(t); ans.PB(a[0]); dfs(s); printf("Case %d:\n", kase++); printf("%lld\n", d[s]); int nc = ans.size(); REP(i, nc) printf("%c%c", ans[i], i == nc-1 ? '\n' : '-'); } return 0; }