HDU[6805] Deliver the Cake 【最短路+建图】

Description

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≤10^5,1≤m≤2×10^5,1≤x≤10^9), 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≤10^9), 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×10^5. The sum of m doesn't exceed 4×10^5. 

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 

题目大意:

给定一张无向图,求从起点到终点的最短路径。其中,每个点有一定限制,规定在该点时必须是以下三种状态之一:

左手拿 或 右手拿 或 左右手拿都可。

在路径中可以进行任意次换手,每次换手花费 x 。

分析:

如果没有条件限制,那么直接就是最短路问题。

比较特殊的是状态为MIDDLE的点,在这样的点左手拿和右手拿虽然都可以,但是其实是两个不同的状态,会对之后的路径产生影响。所以重新建图,把状态为MIDDLE的点拆分成两个点,规定一个点只能用左手拿,另一个点只能用右手拿,然后在建立相应的边。

由于要求的是最短路径,所以在同一条边上最多会换一次手,所以对于两个顶点状态不同的边,边权加 x 。

建图完成后,就利用Dijkstra直接求出最短路。

这里还要注意起点和终点的状态,进行讨论。

具体解释见代码。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <queue>
#define INF 0x3f3f3f3f
#define mst(a,num) memset(a,num,sizeof a)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define repd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef vector<int> VI;
const ll mod = 1e9 + 7;
const int maxn = 100000 + 5;

int n,m,s,t;
ll x;
char str[maxn*2];

struct node{
	int nxt;
    ll w;
};
 
int vis[maxn*2];
ll dis[maxn*2];
vector<node> edge[maxn*2];
 
struct point{
    ll val,id;
    point(ll id,ll val):id(id),val(val) {}
    bool operator <(const point &x)const{ 
        return val>x.val;
    }
};
 
void dijkstra(int s,int e1,int e2){       //最短路采用Dijkstra
    memset(vis,0,sizeof(vis));
    for(int i=1; i<=2*n; i++)
        dis[i]=1e18;
 
    priority_queue<point> q;
    q.push(point(s,0));
    vis[s]=1;
    dis[s]=0;
    while(!q.empty()){
        ll cur=q.top().id;
        q.pop();
        vis[cur]=1;
        if(e2==-1){
            if(vis[e1])  return;
        }
        else{
            if(vis[e1]&&vis[e2])  return;
        }
        for(int i=0; i < edge[cur].size() ; i++){
            int id=edge[cur][i].nxt;
            ll cost=edge[cur][i].w;
            if(!vis[id]&&dis[id]>dis[cur]+cost){
            	dis[id]=dis[cur]+cost;
            	q.push(point(id,dis[id]));
            }
        }
    }
}

int main() {
    int cas;
    scanf("%d",&cas);
    while(cas--){
        scanf("%d%d%d%d%lld",&n,&m,&s,&t,&x);
        scanf("%s",str+1);
        rep(i,1,2*n){
            edge[i].clear();
        }
        int u,v;
        ll w;

        //建图,对于状态为 M 的点 i ,拆分成两个点 i 和 i+n ,规定在 i 点状态为 L ,在 i+n 点状态为 R 

        rep(i,1,m){
            scanf("%d%d%lld",&u,&v,&w);
            if(str[u]=='L'){
                if(str[v]=='L'){
                    edge[u].push_back({v,w});
                    edge[v].push_back({u,w});
                }
                else if(str[v]=='R'){
                    edge[u].push_back({v,w+x});
                    edge[v].push_back({u,w+x});
                }
                else{
                    edge[u].push_back({v,w});
                    edge[u].push_back({v+n,w+x});
                    edge[v].push_back({u,w});
                    edge[v+n].push_back({u,w+x});
                }
            }
            else if(str[u]=='R'){
                if(str[v]=='L'){
                    edge[u].push_back({v,w+x});
                    edge[v].push_back({u,w+x});
                }
                else if(str[v]=='R'){
                    edge[u].push_back({v,w});
                    edge[v].push_back({u,w});
                }
                else{
                    edge[u].push_back({v,w+x});
                    edge[u].push_back({v+n,w});
                    edge[v].push_back({u,w+x});
                    edge[v+n].push_back({u,w});
                }
            }
            else{
                if(str[v]=='L'){
                    edge[u].push_back({v,w});
                    edge[v].push_back({u,w});
                    edge[u+n].push_back({v,w+x});
                    edge[v].push_back({u+n,w+x});
                }
                else if(str[v]=='R'){
                    edge[u].push_back({v,w+x});
                    edge[v].push_back({u,w+x});
                    edge[u+n].push_back({v,w});
                    edge[v].push_back({u+n,w});
                }
                else{
                    edge[u].push_back({v,w});
                    edge[v].push_back({u,w});
                    edge[u].push_back({v+n,w+x});
                    edge[v+n].push_back({u,w+x});
                    edge[v].push_back({u+n,w+x});
                    edge[u+n].push_back({v,w+x});
                    edge[u+n].push_back({v+n,w});
                    edge[v+n].push_back({u+n,w});
                }
            }
        }

        //注意讨论起点和终点的状态
        if(str[s]=='L'){
            if(str[t]=='L'||str[t]=='R'){
                dijkstra(s,t,-1);
                printf("%lld\n",dis[t]);
            }
            else{
                dijkstra(s,t,t+n);
                printf("%lld\n",min(dis[t],dis[t+n]));
            }
        }
        else if(str[s]=='R'){
            if(str[t]=='L'||str[t]=='R'){
                dijkstra(s,t,-1);
                printf("%lld\n",dis[t]);
            }
            else{
                dijkstra(s,t,t+n);
                printf("%lld\n",min(dis[t],dis[t+n]));
            }
        }
        else{
            ll ans=1e18;
            if(str[t]=='L'||str[t]=='R'){
                dijkstra(s,t,-1);
                ans=min(ans,dis[t]);
                dijkstra(s+n,t,-1);
                ans=min(ans,dis[t]);
                printf("%lld\n",ans);
            }
            else{
                dijkstra(s,t,t+n);
                ans=min(ans,min(dis[t],dis[t+n]));
                dijkstra(s+n,t,t+n);
                ans=min(ans,min(dis[t],dis[t+n]));
                printf("%lld\n",ans);
            }
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值