UVa 10537

题目链接:https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=0&problem=1478&mosmsg=Submission+received+with+ID+26584073

每进入村庄或城镇都要收费,已知到要运送到终点的费用,很自然地想到从终点向起点逆推。

逆推的过程类似 (dijstra),每次选出已知收费最少的点进行扩展,重点在于路径收费的计算,可以用数学推式子,也可以二分,最后从起点向后输出字典序最小的路径即可,在路径上的点满足 (d[v] == d[u] + w)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, int> pii;

const int maxn = 105;
const ll INF = 1ll << 60ll;

int n, m;
vector<int> G[maxn];

ll P;
ll g[maxn][maxn];

int ID(char ch){
	if(ch >= 'A' && ch <= 'Z') return ch - 'A' + 1; 
	else return 26 + ch - 'a' + 1;
} 

ll get(ll left){
	ll L = left, R = INF;
	ll res;
	while(L <= R){
		ll mid = (L + R) >> 1;
		ll fre = mid / 20ll;
		if(mid % 20ll != 0) ++fre;
		if(mid - fre >= left){
			R = mid - 1ll;
			res = mid;
		} else if(mid - fre < left){
			L = mid + 1ll;
		}
	}
	return res - left;
}

ll d[maxn];
void dij(int S){
	priority_queue<pii, vector<pii>, greater<pii> > q;
	
	for(int i = 1 ; i <= 52 ; ++i) d[i] = INF;
	d[S] = P;
	
	q.push(pii(d[S], S));
	
	while(!q.empty()){
		pii p = q.top(); q.pop();
		int u = p.second;
		if(d[u] != p.first) continue;
		
		for(int i = 0 ; i < G[u].size() ; ++i){
			int v = G[u][i];
			if(u <= 26){ // town 
				ll val = get(d[u]);
				g[v][u] = val;
				if(d[v] > d[u] + val){
					d[v] = d[u] + val;
					q.push(pii(d[v], v));
				}
			} else{ // village
				g[v][u] = 1ll;
				if(d[v] > d[u] + 1ll){
					d[v] = d[u] + 1ll;
					q.push(pii(d[v], v));
				}
			}
		}
	}
}

vector<char> path;

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	char uu[10], vv[10];
	char s[10], t[10];
	int kase = 0;
	while(scanf("%d", &n) == 1 && n != -1){
		memset(g, 0, sizeof(g));
		path.clear();
		for(int i = 1 ; i <= 52 ; ++i) G[i].clear();
		for(int i = 1 ; i <= n ; ++i){
			scanf("%s%s", uu, vv);
			G[ID(uu[0])].push_back(ID(vv[0]));
			G[ID(vv[0])].push_back(ID(uu[0]));
		}
		scanf("%lld%s%s", &P, s, t);
		
		dij(ID(t[0]));
		
		printf("Case %d:
", ++kase);
		printf("%lld
", d[ID(s[0])]);
		
		int cur = ID(s[0]);
		while(1){
			path.push_back((cur <= 26) ? cur + 'A' - 1 : cur - 26 + 'a' - 1);
			if(cur == ID(t[0])) break;
			int tmp = 101;
			for(int i = 0 ; i < G[cur].size() ; ++i){
				int v = G[cur][i];
				if(d[cur] == d[v] + g[cur][v]){
					tmp = min(tmp, v);
				}
			} 
			cur = tmp;
		} 
		int tt = 0;
		for(auto u : path){
			if(tt) printf("%c", '-');
			tt = 1;
			printf("%c", u);
		} printf("
");
	}
	return 0;
}
原文地址:https://www.cnblogs.com/tuchen/p/15026585.html