【UVA10537】The Toll! Revisited

来源:互联网 发布:小程序跳转到淘宝app 编辑:程序博客网 时间:2024/05/14 22:22

题意

给定图G=VEV中有两类点,一类点(A类)在进入时要缴纳1的费用,另一类点(B类)在进入时要缴纳当前携带金额的120(不足20的部分按20算)
  已知起点为S,终点为T,希望在到达T时能够拥有P的金额,问一开始在S最少要携带多少金额,并求出路径(若有多条,输出字典序最小的)
  从S离开时不需要缴费,进入T时需要缴费

解法

spfa变异最短路:
  其实这道题的难点就在于怎么求出花费,其他的过程则和正常的spfa一模一样,至于输出路径就记一个Pre即可
  考虑一条从TS的路径,假设当前点为u,要前往的点为v,那么按u的种类分情况讨论:
  如果uA类点,那么从u前往v的花费显然是disu+1
  如果uB类点,那么从u前往v花费就是:x=disu2019whilexx+1920disux++,最后的x就是从uv的花费,不过下面的代码不是这么写的,比较鬼畜……
  然后倒着做spfa即可

复杂度

O(|V||E|

代码

#include<iostream>#include<cstdlib>#include<cstring>#include<cstdio>#include<queue>#define Rint register int#define Lint long long intusing namespace std;const Lint INF=1e18;const int E=50010;const int N=1010;struct node{    int next,from,to;}t[E];int head[N],num;int Pre[N],vis[N];Lint dis[N];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;}
原创粉丝点击