• 迪杰斯特拉+拆点 Deliver the Cake


    题意:

    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 
    ",v[t],v[t+n]);
                ans=min(v[t],v[t+n]);
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    C#操作SQLite 报错 (Attempt to write a readonly database)
    JS判断字符输入个数(数字英文长度记为1,中文记为2,超过长度自动截取)
    JueryUI插件的简单应用(一):介绍及第一个示例
    在VS2008(Winform)中使用WebService
    Oracle触发器使用
    C# 创建Windows服务。服务功能:定时操作数据库
    aspnet前后台条件下根目录的读取
    xshell实现端口转发
    (转)使用FreeType实现矢量字体的粗体、斜体、描边、阴影效果
    D3D坐标系统和几何DirectX Griaphic学习
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/13418466.html
Copyright © 2020-2023  润新知