hdu 4360 As long as Binbin loves Sangsang

题目大意:

n(1<=N<=1,314)个点,m(0<=M<=13,520)条边,每个边除了有长度之外,还有一个字母来标记,分别是L,O,V,E中的一个,要求求出从1到n的一条最短路,还要保证走的路径是L->0->V->E->L->……且最后得到的路径必须是完整的LOVE的相加,在最短路长度相同的情况下,要求LOVE尽可能多。

题解:

将一个点,拆成4个点,同时开一个数组let[i]表示到i为止的最短路经过的最大边数,然后使用spfa即可,此时spfa中的三角形不等式要有所变化,见程序。

此题的坑是:当n等于1时,spfa不能求出正确的解,需要特判,且还要注意重边。

#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
const long long  inf=11111111111111111LL;
long long d[8000],let[8000];
int to[80000],cap[80000],next[80000],edge[80000];
int n,m,em,sec;
bool v[8000];
queue<int> q;
void addedge(int x,int y,int d)
{
    em++;
    to[em]=y;
    cap[em]=d;
    next[em]=edge[x];
    edge[x]=em;
}
void spfa(int s,int n)
{
    for(int i=0;i<=n;i++)
    {
        d[i]=inf;
        v[i]=false;
    }
    d[s]=0;v[s]=true;q.push(s);
    while(!q.empty())
    {
        int x=q.front();q.pop();
        int p=edge[x];
        while(p!=-1)
        {
            if(d[x]<inf && (d[x]+cap[p]<d[to[p]] || (d[x]+cap[p]==d[to[p]] && let[x]+1>let[to[p]])))//最短路相同时,比较let
            {
                d[to[p]]=d[x]+cap[p];
                let[to[p]]=let[x]+1;
                if(!v[to[p]])
                {
                    v[to[p]]=true;
                    q.push(to[p]);
                }
            }
            p=next[p];
        }
        v[x]=false;
    }
}
int main()
{
    scanf("%d",&sec);
    for(int z=1;z<=sec;z++)
    {
        scanf("%d%d",&n,&m);
        em=0;
        for(int i=0;i<=m*4+1;i++)
        {
            edge[i]=-1;
            next[i]=-1;
        }
        int x,y,tx,ty,dis,c;
        char tc;
        if(n>1)
        {
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d %c",&tx,&ty,&dis,&tc);
            if(tc=='L')c=0;else
            if(tc=='O')c=1;else
            if(tc=='V')c=2;else
            if(tc=='E')c=3;
            x=((c+3)%4)*n+tx;y=c*n+ty;
            addedge(x,y,dis);
            y=((c+3)%4)*n+ty;x=c*n+tx;
            addedge(y,x,dis);
        }
        memset(let,0,sizeof(let));
        spfa(3*n+1,4*n);
        }
        else
        {//特判
            long long g[5][5];
            for(int i=1;i<=4;i++)
             for(int j=1;j<=4;j++)
             g[i][j]=inf;
            for(int i=1;i<=m;i++)
            {
                scanf("%d%d%d %c",&tx,&ty,&dis,&tc);
                if(tc=='L')c=0;else
                if(tc=='O')c=1;else
                if(tc=='V')c=2;else
                if(tc=='E')c=3;
                x=((c+3)%4)*n+tx;y=c*n+ty;
                if(dis<g[x][y])g[x][y]=dis;//去重边
                y=((c+3)%4)*n+ty;x=c*n+tx;
                if(dis<g[y][x])g[y][x]=dis;
            }
            for(int k=1;k<=4;k++)
             for(int i=1;i<=4;i++)
              for(int j=1;j<=4;j++)
              if(g[i][k]+g[k][j]<g[i][j])g[i][j]=g[i][k]+g[k][j];
            d[4]=g[4][4];
            let[4]=4;
        }
        printf("Case %d: ",z);
        if(d[4*n]<inf)
        {
            printf("Cute Sangsang, Binbin will come with a donkey after travelling %I64d meters and finding %I64d LOVE strings at last.\n",d[4*n],let[4*n]/4);
        }
        else
        {
            printf("Binbin you disappoint Sangsang again, damn it!\n");
        }
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值