DIJ(拆点) - Deliver the Cake - HDU 6805

DIJ(拆点) - Deliver the Cake - HDU 6805

2020 Multi-University Training Contest 4

题意:

给 定 一 个 n 个 点 , m 条 边 的 无 向 带 权 图 , 给定一个n个点,m条边的无向带权图, nm

点 的 类 型 分 为 三 种 : L , R , M 点的类型分为三种:L,R,M L,R,M

到 达 L / R 点 时 必 须 保 持 状 态 L / R , 在 M 点 可 以 是 任 意 状 态 。 到达L/R点时必须保持状态L/R,在M点可以是任意状态。 L/RL/RM

从 状 态 L / R 切 换 至 R / L 需 要 的 花 费 为 x , 从状态L/R切换至R/L需要的花费为x, L/RR/Lx

现 计 算 从 s 点 到 t 点 的 最 少 花 费 是 多 少 。 现计算从s点到t点的最少花费是多少。 st

输入:

T 组 测 试 数 据 , T组测试数据, T

首 行 包 含 五 个 正 整 数 : n , m , s , t , x , 首行包含五个正整数:n,m,s,t,x, n,m,s,t,x

接 着 一 行 长 度 为 n 的 字 符 串 , 依 次 表 示 每 个 点 的 类 型 , 接着一行长度为n的字符串,依次表示每个点的类型, n

最 后 m 行 , 每 行 包 括 三 个 正 整 数 a i , b i , d i , 表 示 点 a i 和 b i 之 间 有 一 条 权 值 为 d i 的 边 。 最后m行,每行包括三个正整数a_i,b_i,d_i,表示点a_i和b_i之间有一条权值为d_i的边。 mai,bi,diaibidi

输出:

一 个 正 整 数 , 表 示 从 s 点 到 t 点 的 最 少 花 费 。 一个正整数,表示从s点到t点的最少花费。 st

Sample Input

1
3 3 1 3 100
LRM
1 2 10
2 3 10
1 3 100

Sample Output

100

数据范围:

1 ≤ T ≤ 100 , 1 ≤ n ≤ 1 0 5 , 1 ≤ m ≤ 2 × 1 0 5 , 1 ≤ x ≤ 1 0 9 , 1 ≤ d i ≤ 1 0 9 1≤T≤100,1≤n≤10^5,1≤m≤2×10^5,1≤x≤10^9,1≤d_i≤10^9 1T1001n1051m2×1051x1091di109

The sum of n in all test cases doesn’t exceed 2×105. The sum of m doesn’t exceed 4×105.


分析:

本 题 由 于 存 在 M 类 型 的 点 , 造 成 了 两 点 之 间 代 价 的 不 确 定 。 本题由于存在M类型的点,造成了两点之间代价的不确定。 M

若 两 点 的 类 型 不 同 , 一 个 是 L , 一 个 是 R , 那 么 经 过 这 两 点 之 间 的 边 , 需 要 额 外 的 代 价 x , 若两点的类型不同,一个是L,一个是R,那么经过这两点之间的边,需要额外的代价x, LRx

我 们 将 代 价 x 累 加 到 边 权 上 去 。 我们将代价x累加到边权上去。 x

对 于 M 类 型 的 点 u , 我 们 将 其 拆 分 成 两 个 点 来 L 和 R 来 看 待 。 对于M类型的点u,我们将其拆分成两个点来L和R来看待。 MuLR

如何拆点?

可 以 通 过 增 加 偏 移 量 的 方 法 , 将 编 号 u 映 射 为 L 类 型 的 点 , 编 号 u + n 映 射 为 R 类 型 的 点 。 可以通过增加偏移量的方法,将编号u映射为L类型的点,编号u+n映射为R类型的点。 uLu+nR

那 么 对 于 任 意 两 个 相 邻 的 点 u 和 v , 设 它 们 之 间 的 边 权 为 w , 共 有 3 × 3 = 9 种 建 边 的 可 能 : 那么对于任意两个相邻的点u和v,设它们之间的边权为w,共有3×3=9种建边的可能: uvw3×3=9

① 、 u 和 v 的 类 型 均 为 L 或 均 为 R : 在 u 和 v 之 间 建 一 条 权 值 为 w 的 无 向 边 。 ①、u和v的类型均为L或均为R:在u和v之间建一条权值为w的无向边。 uvLRuvw

② 、 u 和 v 的 类 型 一 个 为 L , 另 一 个 为 R : 在 u 和 v 之 间 建 一 条 权 值 为 w + x 的 无 向 边 。 ②、u和v的类型一个为L,另一个为R:在u和v之间建一条权值为w+x的无向边。 uvLRuvw+x

③ 、 u 为 L , v 为 M : 在 u 和 v 之 间 建 立 权 值 为 w 的 无 向 边 , u 和 v + n 之 间 建 立 权 值 为 w + x 的 无 向 边 。 ③、u为L,v为M:在u和v之间建立权值为w的无向边,u和v+n之间建立权值为w+x的无向边。 uLvMuvwuv+nw+x

④ 、 u 为 M , v 为 L : 在 u 和 v 之 间 建 立 权 值 为 w 的 无 向 边 , u + n 和 v 之 间 建 立 权 值 为 w + x 的 无 向 边 。 ④、u为M,v为L:在u和v之间建立权值为w的无向边,u+n和v之间建立权值为w+x的无向边。 uMvLuvwu+nvw+x

⑤ 、 u 为 R , v 为 M : 在 u 和 v 之 间 建 立 权 值 为 w + x 的 无 向 边 , u 和 v + n 之 间 建 立 权 值 为 w 的 无 向 边 。 ⑤、u为R,v为M:在u和v之间建立权值为w+x的无向边,u和v+n之间建立权值为w的无向边。 uRvMuvw+xuv+nw

⑥ 、 u 为 M , v 为 R : 在 u 和 v 之 间 建 立 权 值 为 w + x 的 无 向 边 , u + n 和 v 之 间 建 立 权 值 为 w 的 无 向 边 。 ⑥、u为M,v为R:在u和v之间建立权值为w+x的无向边,u+n和v之间建立权值为w的无向边。 uMvRuvw+xu+nvw

⑦ 、 u 为 M , v 为 M : ⑦、u为M,v为M: uMvM

在 u 和 v 之 间 建 立 权 值 为 w 的 无 向 边 , u 和 v + n 之 间 建 立 权 值 为 w + x 的 无 向 边 。 \qquad在u和v之间建立权值为w的无向边,u和v+n之间建立权值为w+x的无向边。 uvwuv+nw+x

在 u + n 和 v 之 间 建 立 权 值 为 w + x 的 无 向 边 , u + n 和 v + n 之 间 建 立 权 值 为 w 的 无 向 边 。 \qquad在u+n和v之间建立权值为w+x的无向边,u+n和v+n之间建立权值为w的无向边。 u+nvw+xu+nv+nw

注意:

当 起 点 或 终 点 是 M 类 型 的 点 时 , 起 点 或 终 点 会 有 两 个 。 当起点或终点是M类型的点时,起点或终点会有两个。 M

此 时 可 建 立 虚 拟 源 点 , 与 起 点 或 终 点 之 间 连 一 条 长 度 为 0 的 边 即 可 。 此时可建立虚拟源点,与起点或终点之间连一条长度为0的边即可。 0

起 点 可 以 取 0 号 虚 拟 源 点 , 终 点 可 取 2 n + 1 号 虚 拟 源 点 ( 因 为 拆 点 将 右 点 都 增 加 了 n 的 偏 移 量 ) 。 起点可以取0号虚拟源点,终点可取2n+1号虚拟源点(因为拆点将右点都增加了n的偏移量)。 02n+1(n)

建 完 图 后 跑 一 遍 d i j k s t r a 算 法 即 可 。 建完图后跑一遍dijkstra算法即可。 dijkstra

代码:

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>

#define ll long long
#define P pair<ll,int>
#define x first
#define y second

using namespace std;

const int N=2e5+10, M=2e6+10, inf=0x3f3f3f3f;

int T,n,m,s,t,x;
int e[M],ne[M],w[M],h[N],idx;
char str[N];
ll dis[N];
bool st[N];

void add(int a,int b,int c)
{
    e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}

int dijkstra()
{
    memset(st,false,sizeof st);
    memset(dis,0x3f,sizeof dis);
    if(str[s]=='M') dis[0]=0;
    else dis[s]=0;
    
    priority_queue<P,vector<P>,greater<P>> heap;
    if(str[s]=='M') heap.push({0,0});
    else heap.push({0,s});
    
    while(heap.size())
    {
        P t=heap.top();
        heap.pop();
        
        int id=t.second;
        if(st[id]) continue;
        st[id]=true;
        
        for(int i=h[id];~i;i=ne[i])
        {
            int j=e[i];
            if(dis[j]>dis[id]+w[i])
            {
                dis[j]=dis[id]+w[i];
                heap.push({dis[j],j});
            }
        }
    }
    
    if(str[t]=='M') return dis[2*n+1];
    return dis[t];
}

int main()
{  
    scanf("%d",&T);
    while(T--)
    {
        idx=0;
        memset(h,-1,sizeof h);   
        
        scanf("%d%d%d%d%d",&n,&m,&s,&t,&x);
        scanf("%s",str+1);
        if(str[s]=='M') 
        {
            add(0,s,0), add(s,0,0);
            add(0,s+n,0), add(s+n,0,0);
        }
        if(str[t]=='M')
        {
            add(2*n+1,t,0), add(t,2*n+1,0);
            add(2*n+1,t+n,0), add(t+n,2*n+1,0);
        }

        int a,b,c;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            if((str[a]=='L'&&str[b]=='R') || (str[a]=='R'&&str[b]=='L'))
            {
                add(a,b,c+x), add(b,a,c+x); //LR or RL
            }
            else if((str[a]=='L'&&str[b]=='L') || (str[a]=='R'&&str[b]=='R'))
            {
                add(a,b,c), add(b,a,c); //LL or RR
            }
            else if(str[a]=='L'&&str[b]=='M')
            {
                add(a,b,c), add(b,a,c);     // LL
                add(a,n+b,c+x), add(n+b,a,c+x); //LR
            }
            else if(str[a]=='M'&&str[b]=='L')
            {
                add(a,b,c), add(b,a,c); //LL
                add(a+n,b,c+x), add(b,a+n,c+x); //RL
            } 
            else if(str[a]=='R'&&str[b]=='M')
            {
                add(a,b,c+x), add(b,a,c+x); //RL
                add(a,n+b,c), add(n+b,a,c); //RR
            }
            else if(str[a]=='M'&&str[b]=='R')
            {
                add(a,b,c+x), add(b,a,c+x); //LR
                add(a+n,b,c), add(b,a+n,c); //RR
            }
            else if(str[a]=='M'&&str[b]=='M')
            {
                add(a,b,c), add(b,a,c);         //LL
                add(a,b+n,c+x), add(b+n,a,c+x); //LR
                add(a+n,b,c+x), add(b,a+n,c+x); //RL
                add(a+n,b+n,c), add(b+n,a+n,c); //RR
            }
        }
        
        printf("%lld\n",dijkstra());
    }
    
    return 0;
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值