Deliver the Cake

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 n n villages, labeled 1 , 2 , … , n 1,2,…,n 1,2,,n. There are m bidirectional roads, the ith of which connects village a i ai ai, b i bi bi and it is d i di di meter(s) long.
The bakery locates at village s s s and Zhang3’s home locates at village t t t. So Zhang3 wants to carry the cake from s s s to t t 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 x 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 L E F T LEFT LEFT. When Zhang3 is at a L E F T LEFT LEFT village, she must carry the cake with her left hand at the moment. In the same way, some other villages are R I G H T RIGHT RIGHT, she must carry with her right hand when she’s at these villages. The rest villages are called M I D D L E MIDDLE MIDDLE. There’s no special rules at M I D D L E MIDDLE MIDDLE villages.
Zhang3 can start and finish with any hand carrying the cake. However, if s s s or t t t is not M I D D L E MIDDLE 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.\

题目描述 翻译

今天是张三的生日,于是,张三去买了一个生日蛋糕,现在该取回家了。
这里一共有 n n n 个村庄,每个村庄编号记为 1 , 2 , . . . , n 1,2,...,n 1,2,...,n 在这个村庄中,共有 m m m 条双向道路,连接 a i a_{i} ai b i b_{i} bi 村,长度为 d i d_{i} di 米。
面包店在 s s s 村,张三的家在 t t t 村,所以,张三需要把蛋糕从 s s s 村带到 t t t 村。
她可以用自己的左手拿蛋糕,也可以用右手,也可以在路途中交换拿蛋糕的手,但这需要花费她 x x x 秒的时间(当她交换拿蛋糕的手时,只能站在原地)。在任何地方,任何时间,她都可以交换拿蛋糕的手,她也可以随心所欲地交换很多次,也可以不交换。
但是,这 n n n 个村庄中,有一些 L E F T LEFT LEFT 村庄,张三在经过 L E F T LEFT LEFT 村庄时,必须用左手拿生日蛋糕,同样的,这里还有一些 R I G H T RIGHT RIGHT 村庄,在经过这些 R I G H T RIGHT RIGHT 村庄时,必须用右手拿生日蛋糕。其余的村庄则是 M I D D L E MIDDLE MIDDLE 村庄,经过这些村庄,左手右手拿都可以。
张三在开始和结束时,用左手或右手拿蛋糕都可以。当然,如果村庄 s s s 或村庄 t t t L E F T LEFT LEFT R I G H T RIGHT RIGHT 村庄的话,也必须要遵守这些村庄的规则。
现在,请你帮忙计算张三带蛋糕回家最少需要花费的时间

题目描述 大意:

给定一个 n n n个点, m m m条边的无向带权图,点的类型分为三种: L , R , M L,R,M L,R,M
到达 L L L 点时必须保持状态 L L L,到达 R R R 点时必须保持状态 R R R,在M点可以是任意状态。
从状态 L L L 切换至 R R R 需要的花费为 x x x,从状态 R R R 切换至 L L L 需要的花费也为 x x x
现计算从 s s s 点到 t t t 点的最少花费是多少。现计算从 s s s 点到 t t t 点的最少花费是多少。

输入格式

The first line of the input gives the number of test cases, T ( 1 ≤ T ≤ 100 ) T(1≤T≤100) T(1T100). T T T test cases follow.
For each test case:
the first line contains five integers n , m , s , t , x ( 1 ≤ n ≤ 1 0 5 , 1 ≤ m ≤ 2 × 1 0 5 , 1 ≤ x ≤ 1 0 9 ) n,m,s,t,x(1≤n≤10^{5},1≤m≤2×10^{5},1≤x≤10^{9}) n,m,s,t,x(1n105,1m2×105,1x109), 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 n n, describing the type of each village. The ith character is either L L L representing village i i i is L E F T LEFT LEFT, or M M M representing M I D D L E MIDDLE MIDDLE, or R R R representing R I G H T RIGHT RIGHT.
Finally, m m m lines follow, the ith of which contains three integers a i , b i , d i ( 1 ≤ d i ≤ 1 0 9 ) ai,bi,di(1≤di≤10^9) ai,bi,di(1di109), 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 × 1 0 5 2×10^{5} 2×105. The sum of m doesn’t exceed 4 × 1 0 5 4×10^{5} 4×105.

输入格式 翻译

第一行输入一个数字 T ( 1 ≤ T ≤ 100 ) T(1 \leq T \leq 100) T(1T100),表示测试数据数量。
对于每组测试数据:
第一行输入 5 5 5 个整数 n , m , s , t , x ( 1 ≤ n ≤ 1 0 5 , 1 ≤ m ≤ 2 × 1 0 5 , 1 ≤ x ≤ 1 0 9 ) n, m, s, t, x(1 \leq n \leq 10^{5}, 1 \leq m \leq 2 × 10 ^ {5}, 1 \leq x \leq 10^{9}) n,m,s,t,x(1n105,1m2×105,1x109),分别代表村庄数量,道路数量,面包店位置,张三的家的位置以及每次换手需要的时间。
第二行输入一个长度为 n n n 的字符串,表示每个村庄的类型,第 i i i 个字符 L L L 是表示第 i i i 个村庄是 L E F T LEFT LEFT 村庄, M M M 表示是 M I D D L E MIDDLE MIDDLE 村庄, R R R 表示是 R I G H T RIGHT RIGHT 村庄。
最后,输入 m m m 行,表示 m m m 条道路,第 i i i 行包含三个数字 a i , b i , d i ( 1 ≤ d i ≤ 1 0 9 ) a_{i}, b_{i}, d_{i}(1 \leq d_{i} \leq 10^{9}) ai,bi,di(1di109) 表示 a i a_{i} ai b i b_{i} bi 的长度为 d i d_{i} di 米。这里设定张三的行走速度为 1 m / s 1m/s 1m/s
数据保证村庄 t t t 出发肯定能够到达村庄 s s s
对于每个测试文件,数据保证 n n n 的总和不超过 2 × 1 0 5 2 × 10^{5} 2×105 m m m 的总和不超过 4 × 1 0 5 4 × 10^{5} 4×105

输出格式

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

输入格式翻译

对于每个测试用例,请打印一个带有整数的行,该行表示所花费的最短时间(以秒为单位)。

样例
样例输入

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

样例输出

100


分析

如果这道题没有 L E F T 村庄 LEFT村庄 LEFT村庄 R I G H T 村庄 RIGHT村庄 RIGHT村庄 M I D D L E 村庄 MIDDLE村庄 MIDDLE村庄 的限制,这道题就是最短路的板题了。
我们可以把每个村庄分成两个小村庄, L E F T 村庄 LEFT村庄 LEFT村庄 分成两个 L E F T 小村庄 LEFT小村庄 LEFT小村庄 R I G H T 村庄 RIGHT村庄 RIGHT村庄 分成两个 R I G H T 小村庄 RIGHT小村庄 RIGHT小村庄 M I D D L E 村庄 MIDDLE村庄 MIDDLE村庄 分成两个 L E F T 小村庄 LEFT小村庄 LEFT小村庄 R I G H T 小村庄 RIGHT小村庄 RIGHT小村庄
在按照Dijkstra的算法求出最短路,只不过需要判断一下 小村庄 u 小村庄u 小村庄u 小村庄 v 小村庄v 小村庄v 是否为不同的小村庄(即判断是否是 一个 L E F T 小村庄 LEFT小村庄 LEFT小村庄,一个 R I G H T 小村庄 RIGHT小村庄 RIGHT小村庄)

  • 如果是的话,就将 w [ u ] [ v ] w[u][v] w[u][v] 加上 x x x
  • 不是就不加了

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;

const int MAXN = 2e5 + 5; // 因为每个村庄要分成两个小村庄, 所以 MAXN要开2倍 
int TT;
int N, M, S, T, X;
char C[MAXN];
struct edge
{
	int V;
	long long W;
	edge(){}
	edge (int v, long long w) { V = v, W = w; }
	friend bool operator < (edge a, edge b) { return a.W > b.W; } // 重载<, 变成小根堆 
};
vector<edge> G[MAXN];
long long dis[MAXN];
bool vis[MAXN];

void addEdge(int u, int v, int w) // 加边 
{
	G[u].push_back(edge(v, w));
	G[v].push_back(edge(u, w));
}

void Dijkstra(int s) // Dijkstra算法 
{
	memset(dis, 0x3f, sizeof(dis));
	priority_queue<edge> q;
	q.push(edge(s, 0)), q.push(edge(s + 1, 0));
	dis[s] = 0, dis[s + 1] = 0;
	while (!q.empty())
	{
		int u = q.top().V; q.pop();
		if (vis[u]) continue;
		vis[u] = 1;
		int siz = G[u].size();
		for (int i = 0; i < siz; i++)
		{
			int v = G[u][i].V;
			long long w = G[u][i].W;
			if (C[u] != C[v]) w += (long long)X; // 如果不同就加x 
			if (dis[u] + w < dis[v])
			{
				dis[v] = dis[u] + w;
				q.push(edge(v, dis[v]));
			}
		}
	}
}

void init()
{
	memset(vis, false, sizeof(vis));
	for (int i = 1; i <= N; i++) G[i].clear();
}

int main()
{
	scanf("%d", &TT);
	for (int i = 1; i <= TT; i++)
	{
		scanf("%d %d %d %d %d\n", &N, &M, &S, &T, &X);
		N *= 2;
		S = S * 2 - 1, T = T * 2 - 1;
		init();
		for (int j = 1; j <= N; j += 2)
		{
			scanf("%c", &C[j]);
			C[j + 1] = C[j];
			if (C[j] == 'M') C[j] = 'L', C[j + 1] = 'R';
			// 分成两个小村庄 
		}
		for (int j = 1; j <= M; j++)
		{
			int A, B, D;
			scanf("%d %d %d", &A, &B, &D);
			A = A * 2 - 1;
			B = B * 2 - 1;
			// 求出每个村庄对应的小村庄 
			addEdge(A, B, D);
			addEdge(A + 1, B, D);
			addEdge(A, B + 1, D);
			addEdge(A + 1, B + 1, D);
			// 将这4个小村庄连起来 
		}
		Dijkstra(S);
		long long ans = min(dis[T], dis[T + 1]);
		// 求出 起点的两个小村庄 到 终点的两个小村庄 的最短路 
		printf("%lld\n", ans);
	}
	return 0;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值