迪杰斯特拉+拆点 Deliver the Cake - HDU 6805

题意:

t组输入,给你n个点m条边。你需要输出从s点到t点的最短距离,然后是m条边,每条边输入信息为:

a,b,c 表示从a点到b点的一个无向边长度为c

每一个点会有一个属性L、R或M

如果a和b一个为L,另一个为R,那么a和b之间的距离要增加x,即变为x+c

其他情况权值还是c

 

题解:

我们可以注意到M类型的点是一个特殊点,无论是L类型还是R类型的点和它相连,它们的距离都不会增加x

那么我么可以把M类型的点拆成两个点,例如a点为M类型的点,那么我们可以把a点变为L类型的点,a+n点变为R类型的点

这个样子去构造一个图,然后如果起点s是一个M类型的点,我们就让起点s和s+n都和0号点连一条权值为0的无向边,然后以0为起点跑一边迪杰斯特拉

否则,就直接以s点为起点跑一边迪杰斯特拉

 

代码:

#include <stack>
#include <queue>
#include <map>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define fi first
#define se second
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
const int INF=0x3f3f3f3f;
ll n,m,v[maxn];
char f[maxn];
struct shudui
{
    ll start,val;
    bool operator < (const shudui y)const
    {
        return val>y.val;
    }
} str1,str2;
priority_queue<shudui>r;
vector<shudui>w[maxn];
void JK(ll st)
{
    memset(v,INF,sizeof(v));
    v[st]=0;
    str1.start=st;
    str1.val=0;
    r.push(str1);
    while(!r.empty())
    {
        ll x,y;
        str1=r.top();
        r.pop();
        x=str1.start;
        y=str1.val;
        if(v[x]<y) continue;
        //说明在这个点再此之后又入队了
        //此次出队的并不是s到这个点的最短路,
        //所以在这次更新前点v所连的点已经更过一次了
        //所以后面也不会进行松弛操作
        ll len=w[x].size();
        for(ll i=0;i<len;++i)
        {
            str2=w[x][i];
            if((v[x]+str2.val<v[str2.start]))
            {
                v[str2.start]=v[x]+str2.val;
                str1.start=str2.start;
                str1.val=v[str2.start];
                r.push(str1);
            }
        }
    }
}
void add_edge(ll a,ll b,ll c)
{
    str2.start=b;
    str2.val=c;
    w[a].push_back(str2);
    str2.start=a;
    w[b].push_back(str2);
}

int main()
{
    ll t;
    scanf("%lld",&t);
    while(t--)
    {
        ll s,t,x;
        scanf("%lld%lld%lld%lld%lld",&n,&m,&s,&t,&x);
        for(ll i=0;i<=2*n;++i)
            w[i].clear();
        scanf("%s",f+1);
        while(m--)
        {
            ll a,b,c;
            scanf("%lld%lld%lld",&a,&b,&c);
            if(f[a]==f[b]&&(f[a]=='L'||f[b]=='R'))
            {
                add_edge(a,b,c);
            }
            else if(f[a]!=f[b]&&f[a]!='M'&&f[b]!='M')
            {
                add_edge(a,b,c+x);
            }
            else if(f[a]=='L'&&f[b]=='M')
            {
                add_edge(a,b,c);
                add_edge(a,b+n,c+x);
            }
            else if(f[a]=='M'&&f[b]=='L')
            {
                add_edge(a,b,c);
                add_edge(a+n,b,c+x);
            }
            else if(f[a]=='R'&&f[b]=='M')
            {
                add_edge(a,b,c+x);
                add_edge(a,b+n,c);
            }
            else if(f[a]=='M'&&f[b]=='R')
            {
                add_edge(a+n,b,c);
                add_edge(a,b,c+x);
            }
            else
            {
                add_edge(a,b,c);
                add_edge(a,b+n,c+x);
                add_edge(a+n,b,c+x);
                add_edge(a+n,b+n,c);
            }
        }
        ll ans=0;
        if(f[s]=='M')
        {
            add_edge(0,s,0);
            add_edge(0,s+n,0);
            JK(0);
            ans=min(v[t],v[t+n]);
        }
        else
        {
            JK(s);
            //printf("%lld %lld \n",v[t],v[t+n]);
            ans=min(v[t],v[t+n]);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

posted @ 2020-08-02 12:44  kongbursi  阅读(162)  评论(0编辑  收藏  举报