2020杭電多校第四場 1004 Deliver the Cake

題目

在這裏插入圖片描述
題目連接
php

題目大意是:
給定一張無向有權圖,已知其起點和終點,每一個節點有方向LR或M。蛋糕每次換手須要必定時間x。在方向爲L或R的節點,蛋糕必須在對應的手上,而方向爲M的地方則無所謂。
ios

問最終從起點到終點的最短路程是多少。url

拆點+最短路

這道題,一步一步的來分析spa

第一步,若是沒有對點的方向限制,將會是一個很是簡單的最短路問題。如今有了方向限制。.net

第二步,假設當前僅有左右兩種方向的限制。那麼問題也會變得簡單隻須要將兩端方向不同的邊權加上x,這樣就沒有了方向限制,跑第一步便可。code

第三步,考慮到存在方向爲M的點,能夠將其看做是兩個點,一個是方向爲左的點一個是方向爲右的點,將其拆開,與周圍的點從新建邊。blog

在這裏插入圖片描述
通過這樣一頓操做,圖中就沒有方向爲M的點了,剩下的圖就只剩下方向爲左或者右的點了,按照剛剛第二步分析的那樣實現就好。
在這裏插入圖片描述

圖片

須要注意的是,這裏拆點可能會形成邊的數量不少,建議開10被的m。ci

另外,起點和終點有可能被拆成兩個頂點,爲了避免跑屢次最短路,能夠建造一個虛擬起點和終點分別向拆開的起點和終點鏈接長度爲0的邊。get

代碼:

#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int M = 1000060;
const int N = 1000060;
struct E{
    int point;
    int next;
    long long dis; 
}nxt[M];
struct Node{
    int po;
    long long dis;
    
    bool operator < (const Node& o)const{
        return dis > o.dis;
    }
};

priority_queue<Node> q;
int head[N];
int dir[N];
int T,n,m,s1,s2,t1,t2,x,tot,s,t;
char dirC[N];
bool vis[N];

void link(int a,int b,long long dis){
    nxt[++tot] = {b,head[a],dis};
    head[a] = tot;
}

void dfs1(int k){
    vis[k] = true;
    if(dir[k] == 0){
        n++;
        vis[n] = true;
        dir[k] = -1;
        dir[n] = 1;
        
        if(k == s1)s2 = n;
        if(k == t1)t2 = n;
        
        for(int i = head[k],j;i;i = nxt[i].next){
            j = nxt[i].point;
            link(j,n,nxt[i].dis);
            link(n,j,nxt[i].dis);
        }
    }
    for(int i = head[k],j;i;i = nxt[i].next){
        if(vis[nxt[i].point])
            continue;
        dfs1(nxt[i].point);
    }
}

void dfs2(int k){
    vis[k] = true;
    for(int i = head[k];i;i = nxt[i].next){
        nxt[i].dis += (dir[k] != dir[nxt[i].point]) * x;
    }
    for(int i = head[k];i;i = nxt[i].next){
        if(vis[nxt[i].point])
            continue;
        dfs2(nxt[i].point); 
    }
}

void clearVis(){
    for(int i = 1;i <= n;i++){
        vis[i] = false;
    }
}

long long dijkstar(){
    clearVis();
    q.push({s,0});
    
    Node o;
    while(!q.empty()){
        o = q.top();
        q.pop();
        if(vis[o.po]) continue;
        
        if(o.po == t) return o.dis;
        
        vis[o.po] = true;
        
        for(int i = head[o.po],j;i;i = nxt[i].next){
            j = nxt[i].point;
            if(vis[j])    continue;
            q.push({j,o.dis + nxt[i].dis});
        }
    }
}

int main(){
    for(cin >> T;T;T--){
        tot = 0;s2 = t2 = 0; 
        t = s = 0;
        while(!q.empty()) q.pop();
        scanf("%d%d%d%d%d",&n,&m,&s1,&t1,&x);
        scanf("%s",dirC + 1);
        
        for(int i = 1;i <= n;i++){
            
            if(dirC[i] == 'R')
                dir[i] = 1;
            if(dirC[i] == 'L')
                dir[i] = -1;
            if(dirC[i] == 'M')
                dir[i] = 0;
        }
        
        for(int i = 1;i <= n << 1;i++)    head[i] = 0;
            
        for(int i = 1,a,b,dis;i <= m;i++){
            scanf("%d%d%d",&a,&b,&dis);
            link(a,b,dis);
            link(b,a,dis);
        }
        clearVis();
        dfs1(s1);
        s = ++n;t = ++n;
        
        clearVis();
        dfs2(s1);
        if(s2)    dfs2(s2);
                
        link(s,s1,0);
        if(s2)    link(s,s2,0);
        link(t1,t,0);
        if(t2)    link(t2,t,0);
        cout << dijkstar() << endl;
        
    }
}
相關文章
相關標籤/搜索