1. 程式人生 > 實用技巧 >2020杭電多校聯合訓練(第四場) D.Deliver the Cake (分層圖最短路)

2020杭電多校聯合訓練(第四場) D.Deliver the Cake (分層圖最短路)

題面

It is Zhang3's birthday! Zhang3 has bought a birthday cake and now it's time to take it home.

There are n villages, labeled 1,2,…,n. There are m bidirectional roads, the ith of which connects village ai, bi and it is di meter(s) long.

The bakery locates at village s and Zhang3's home locates at village t. So Zhang3 wants to carry the cake from s to t. She can carry the cake either with her left hand or with her right hand. She can switch to the other hand during the trip, which takes extra x second(s) each time (when she's performing this action, she must stay in her place). Switching is allowed at any place, including the middle of the roads. She can do this as many times as she like, or don't do it at all.

Some villages are LEFT. When Zhang3 is at a LEFT village, she must carry the cake with her left hand at the moment. In the same way, some other villages are RIGHT, she must carry with her right hand when she's at these villages. The rest villages are called MIDDLE. There's no special rules at MIDDLE villages.

Zhang3 can start and finish with any hand carrying the cake. However, if s or t is not MIDDLE, their special rules must be followed.

Please help Zhang3 find a way to take the cake home, with the minimum amount of spent time.

Input
The first line of the input gives the number of test cases, T(1≤T≤100). T test cases follow.

For each test case, the first line contains five integers n,m,s,t,x(1≤n≤105,1≤m≤2×105,1≤x≤109), representing the number of villages, the number of roads, the bakery's location, home's location, and the time spent for each switching.

The next line contains a string of length n, describing the type of each village. The ith character is either L representing village i is LEFT, or M representing MIDDLE, or R representing RIGHT.

Finally, m lines follow, the ith of which contains three integers ai,bi,di(1≤di≤109), denoting a road connecting village ai and bi of length di.

It is guaranteed that t can be reached from s.

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

Output
For each test case, print a line with an integer, representing the minimum amount of spent time (in seconds).

Sample Input
1
3 3 1 3 100
LRM
1 2 10
2 3 10
1 3 100

Sample Output
100

思路

如果除掉左右手的限制那麼這就是一個經典的最短路問題。最短路問題加了限制,比如說讓你選擇一些權值改變等等這種情況,在不改變圖結構的情況下求解被修改圖的最短路,那麼我們就可以用分層圖來解決。我們把對每個不同的決策建立不同的圖,相當於建了一個三維的圖,其實有點像dp的思想,就是狀態之間的不斷轉移構成的多層圖。在這個題目中就是加了左右手的限制,所以我們把每個點分裂成兩個狀態,根據下一個點的狀態和當前的點的狀態限制去進行相應的鬆弛操作,最後我們得到的兩種狀態d點的dis陣列元素的值就是我們最後的答案。

程式碼實現

#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
#define rep(i,f_start,f_end) for (int i=f_start;i<=f_end;++i)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define MT(x,i) memset(x,i,sizeof(x) )
#define rev(i,start,end) for (int i=0;i<end;i++)
#define inf 0x3f3f3f3f3f3f3f3f
#define mp(x,y) make_pair(x,y)
#define lowbit(x) (x&-x)
#define MOD 1000000007
#define exp 1e-8
#define N 1000005 
#define fi first 
#define se second
#define pb push_back
typedef long long ll;
typedef pair<int ,int> PII;
ll gcd (ll a,ll b) {return b?gcd (b,a%b):a; }
inline int read() {
    char ch=getchar(); int x=0, f=1;
    while(ch<'0'||ch>'9') {
        if(ch=='-') f = -1;
        ch=getchar();
    } 
    while('0'<=ch&&ch<='9') {
        x=x*10+ch-'0';
        ch=getchar();
    }   return x*f;
}
typedef pair <ll,PII> PIII; 
const int maxn=2e5+7;
vector <PII > G[maxn];
ll dis[maxn][2];
char st[maxn];
int t,s,n,m;
ll cost;

void dijkstra () {
    rep (i,1,n) dis[i][0]=dis[i][1]=inf;
    priority_queue <PIII,vector<PIII>,greater<PIII> > q;
    if (st[s]=='L') q.push (mp (dis[s][0]=0,mp (s,0)));
    else if (st[s]=='R') q.push (mp (dis[s][1]=0,mp (s,1)));
    else {
        q.push (mp (dis[s][0]=0,mp (s,0)));
        q.push (mp (dis[s][1]=0,mp (s,1)));
    } 
    while (q.size ()) {
        auto p=q.top ();
        q.pop ();
        ll d=p.first;
        int u=p.second.first;
        int tp=p.second.second;
        if (d!=dis[u][tp]) continue;
        for (auto &e: G[u]) {
            int v=e.first,w=e.second;
            if (st[v]=='L') {
                if (tp==0) {
                    if (dis[v][0]>dis[u][0]+w) {
                        dis[v][0]=dis[u][0]+w;
                        q.push (mp (dis[v][0],mp (v,0)));
                    }
                }
                else if (tp==1) {
                    if (dis[v][0]>dis[u][1]+w+cost) {
                        dis[v][0]=dis[u][1]+w+cost;
                        q.push (mp (dis[v][0],mp (v,0)));
                    }
                }
            }
            else if (st[v]=='R') {
                if (tp==1) {
                    if (dis[v][1]>dis[u][1]+w) {
                        dis[v][1]=dis[u][1]+w;
                        q.push (mp (dis[v][1],mp (v,1)));
                    }
                }
                else {
                    if (dis[v][1]>dis[u][0]+cost+w) {
                            dis[v][1]=dis[u][0]+cost+w;
                            q.push (mp (dis[v][1],mp (v,1)));
                        }
                }
            }
            else {
               if (dis[v][tp]>dis[u][tp]+w) {
                        dis[v][tp]=dis[u][tp]+w;
                        q.push (mp (dis[v][tp],mp (v,tp)));
                    }
                    if (dis[v][tp^1]>dis[u][tp]+w+cost) {
                        dis[v][tp^1]=dis[u][tp]+w+cost;
                        q.push (mp (dis[v][tp^1],mp (v,tp^1)));
                    }
            }
        }
    }
}

void solve () {
    cin>>n>>m>>s>>t>>cost;
    scanf ("%s",st+1);
    rep (i,1,n) G[i].clear ();
    rep (i,1,m) {
        int x,y,z;
        scanf ("%d %d %d",&x,&y,&z);
        G[x].pb (mp (y,z));
        G[y].pb (mp (x,z));
    }
    dijkstra ();
    cout<<min (dis[t][1],dis[t][0])<<endl;
}

int main () {
   int t;
   cin>>t;
   while (t--) {
       solve ();
   }
    return 0;
}