题目链接:UVA 10537
解题思路:
这题是大白书上的最短路例题,应用情景非常经典。首先我们在计算最短路的时候需要从终点算起,因为图中边的权值是变化的;计算的方法是一个坑,大概就是对于一个整数N,求一个整数M,使得
N=M−⌈M/20⌉
式子是这样的
M=⌈19N/20⌉
,公式的得出需要先考虑M可以被20整除的情况,然后再考虑不可以整除;最后就是记录并打印路径,这一点需要在最短路计算过程中得出,并且要记下字典序最小的路径。
AC代码:
#include <vector>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int n=52;
const long long INF=1e12+1;
int m,s,t,pre[n+5],vis[n+5],a[n+5][n+5];
int x,y,w;
long long d[n+5];
int ch2int(char ch){
if(ch>'Z')
return ch-'a'+26;
return ch-'A';
}
char int2ch(int num){
if(num>=26)
return char(num-26+'a');
else
return char(num+'A');
}
long long dist(int index,long long input){
long long t=0,p=input;
if(index<26)
{
return (long long)ceil(input*1.0/19*20);
}
else
t=1;
return input+t;
}
void dijkstra(int s)
{
for(int i=0;i<n;i++)
d[i]=INF, vis[i]=0, pre[i]=100;
d[s]=w;
for(int i=0;i<n;i++)
{
long long m=INF;
int index=-1;
for(int j=0;j<n;j++)
{
if(!vis[j]&&m>d[j])
{
m=d[index=j];
}
}
if(index==-1)
break;
vis[index]=1;
long long tmp=dist(index, d[index]);
for(int j=0;j<n;j++)
{
if(!vis[j]&&a[index][j])
{
if(d[j]>tmp||d[j]==tmp&&pre[j]>index)
{
d[j]=tmp;
pre[j]=index;
}
}
}
}
}
int main()
{
int cas=1;
while(~scanf("%d",&m))
{
if(m==-1)
break;
getchar();
char ch1,ch2;
memset(a,0,sizeof(a));
for(int i=0;i<m;i++)
{
scanf("%c %c",&ch1,&ch2);
x=ch2int(ch1), y=ch2int(ch2);
a[x][y]=a[y][x]=1;
getchar();
}
scanf("%d %c %c",&w,&ch1,&ch2);
s=ch2int(ch1), t=ch2int(ch2);
dijkstra(t);
printf("Case %d:\n",cas++);
printf("%lld\n%c",d[s],int2ch(s));
int tmp=pre[s];
while(tmp!=t&&tmp!=100)
{
printf("-%c",int2ch(tmp));
tmp=pre[tmp];
}
if(s!=t)
printf("-%c",int2ch(t));
printf("\n");
}
return 0;
}