您的位置:首页 > 其它

【UVA10537】The Toll! Revisited

2017-10-17 17:21 399 查看
题意

给定图G=(V,E),V中有两类点,一类点(A类)在进入时要缴纳1的费用,另一类点(B类)在进入时要缴纳当前携带金额的120(不足20的部分按20算)

  已知起点为S,终点为T,希望在到达T时能够拥有P的金额,问一开始在S最少要携带多少金额,并求出路径(若有多条,输出字典序最小的)

  从S离开时不需要缴费,进入T时需要缴费

解法

spfa变异最短路:

  其实这道题的难点就在于怎么求出花费,其他的过程则和正常的spfa一模一样,至于输出路径就记一个Pre即可

  考虑一条从T到S的路径,假设当前点为u,要前往的点为v,那么按u的种类分情况讨论:

  如果u为A类点,那么从u前往v的花费显然是disu+1

  如果u为B类点,那么从u前往v花费就是:x=disu∗2019,while(x−x+1920<disu)x++,最后的x就是从u到v的花费,不过下面的代码不是这么写的,比较鬼畜……

  然后倒着做spfa即可

复杂度

O(|V|∗|E|)

代码

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<queue>
#define Rint register int
#define Lint long long int
using namespace std;
const Lint INF=1e18;
const int E=50010;
const int N=1010;
struct node
{
int next,from,to;
}t[E];
int head
,num;
int Pre
,vis
;
Lint dis
;
int n,S,T;
Lint p;
queue<int> q;
void add(int u,int v)
{
t[++num]=(node){ head[u],u,v };
head[u]=num;
}
Lint cal(Lint w)
{
Lint u,num,y;
u=w%20;
if( !u )   u=w/20;
else   u=w/20+1;
num=u*20;
while( w+u>num )
{
y=(w+u)%20;
u= !y ? (w+u)/20 : (w+u)/20+1 ;
num=u*20;
}
return u;
}
void spfa()
{
int tmp;
for(int i=1;i<=120;i++)   dis[i]=INF,Pre[i]=vis[i]=0;
dis[T]=p,q.push( T );
while( !q.empty() )
{
tmp=q.front(),q.pop();
vis[tmp]=0;
for(int i=head[tmp],x; i ;i=t[i].next)
{
x=t[i].to;
if( tmp>=27 && ( dis[x]>dis[tmp]+1 || ( dis[x]==dis[tmp]+1 && t[Pre[x]].from>tmp ) ) )
{
dis[x]=dis[tmp]+1;
Pre[x]=i;
if( !vis[x] )   vis[x]=1,q.push( x );
}
if( tmp<=26 && ( dis[x]>dis[tmp]+cal( dis[tmp] ) || ( dis[x]==dis[tmp]+cal( dis[tmp] ) && t[Pre[x]].from>tmp ) ) )
{
dis[x]=dis[tmp]+cal( dis[tmp] );
Pre[x]=i;
if( !vis[x] )   vis[x]=1,q.push( x );
}
}
}
printf("%lld\n",dis[S]);
printf("%c",S-1+'A');
for(int i=t[Pre[S]].from; i ;i=t[Pre[i]].from)   printf("-%c",i-1+'A');
printf("\n");
}
int main()
{
char a[10],b[10];
int u,v,C=0;
while( scanf("%d",&n)!=EOF )
{
if( n==-1 )   break ;
num=0;
memset( head,0x0,sizeof head );
for(int i=1;i<=n;i++)
{
scanf("%s%s",a,b);
u=a[0]-'A'+1,v=b[0]-'A'+1;
add( u,v ),add( v,u );
}
scanf("%lld%s%s",&p,a,b);
S=a[0]-'A'+1,T=b[0]-'A'+1;
printf("Case %d:\n",++C);
spfa();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: