题目大意
第一行给出N说明有N条路;
接下来n行字母对(a,b)大写表示城镇小写表示村庄村庄税收为1,城镇税收为1/20向上取整;
然后是一个数字和初始城镇目的城镇;求出耗费最小的路径并打出字典序最小的
倒着求
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<string>
#include<queue>
#include<utility>
using namespace std;
typedef long long LL;
#define MAXN 210
const LL INF=1LL<<60;
vector<int> g[200];
int k,m,vis[MAXN];
LL h[MAXN];
void add(int u,int v)
{
g[u].push_back(v);
g[v].push_back(u);
}
LL maintain(char u ,LL x)
{
if(isupper(u)) return x-(x+19)/20;
return x-1;
}
LL cost(char u)
{
if(islower(u)) return h[u]+1;
LL tmp=h[u]*20/19;
while(maintain(u,tmp)<h[u]) tmp++;
return tmp;
}
void dijkstra(int s,int ed)
{
int i,j,u;
for(int i=1; i<=200; i++)
h[i]=INF,vis[i]=0;
h[s]=k,vis[s]=1;
for(int i=0; i<g[s].size(); i++)
h[g[s][i]]=cost(s);
for(i=1; i<=200; i++)
{
if(vis[ed]) break;
LL min=INF;
for(j=1; j<=200; j++)
if(!vis[j] && h[j]<=min)
{
u=j;
min=h[j];
}
if(min==INF) break;
vis[u]=1;
for(int j=0; j<g[u].size(); j++)
{
int v=g[u][j];
if(!vis[v]&&h[v]>=cost(u)) h[v]=cost(u);
}
}
}
int main()
{
int cs=1;
while(~scanf("%d",&m)&&m!=-1)
{
char u[6],v[6];
for(int i='A'; i<='Z'; i++)
g[i].clear();
for(int i='a'; i<='z'; i++)
g[i].clear();
for(int i=0; i<m; i++)
{
scanf("%s%s",u,v);
add(u[0],v[0]);
}
for(int i='A'; i<='Z'; i++)
sort(g[i].begin(),g[i].end());
for(int i='a'; i<='z'; i++)
sort(g[i].begin(),g[i].end());
scanf("%d%s%s",&k,u,v);
dijkstra(v[0],u[0]);
printf("Case %d:\n",cs++);
printf("%lld\n",h[u[0]]);
printf("%c",u[0]);
char pre=u[0];
while(pre!=v[0])
{
for(int i=0; i<g[pre].size(); i++)
{
char to=g[pre][i];
if(maintain(to,h[pre])==h[to] )
{
pre=to;
break;
}
}
printf("-%c",pre);
}
printf("\n");
}
return 0;
}