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

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

2020 Multi-University Training Contest 4

题意:

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

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

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

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

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

输入:

T T组测试数据,

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

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的边。

输出:

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

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

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


分析:

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

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

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

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

如何拆点?

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

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

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

u v L R u v w + x ②、u和v的类型一个为L,另一个为R:在u和v之间建一条权值为w+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的无向边。

u M v L u v w u + n v w + x ④、u为M,v为L:在u和v之间建立权值为w的无向边,u+n和v之间建立权值为w+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的无向边。

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

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

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

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

注意:

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

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

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

d i j k s t r a 建完图后跑一遍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;
}

猜你喜欢

转载自blog.csdn.net/njuptACMcxk/article/details/107701040