LuoguP3946 ことりのおやつ(小鸟的点心) 题解

Content

现给定一个有 \(n\) 个点和 \(m\) 条边的双向地图,起点 \(s\)、目标点 \(t\),两个系数 \(g,q\),还有每个点的两个系数 \(h_i,l_i\),解释如下。

这座城市经常下雪,今天亦是如此。每秒钟会积上厚度为 \(q\) 的雪。第 \(i\) 个点在之前就已经积了厚度为 \(h_i\) 的雪,并且当积雪厚度大于 \(l_i\) 时无法行走。甜品店在 \(s\) 点,小 K 的家在 \(t\) 点。现在,小 K 想要知道在行走长度不超过 \(g\) 的情况下,从甜品店到她家的最短路径长度。如果小 K 没法回去,输出 "wtnapは小鳥のおやつです!"(日语手动狗头) wtnap wa kotori no oyatsu desu!

数据范围:\(2\leqslant n\leqslant 100000\)\(1\leqslant m\leqslant 500000\)\(1\leqslant s\)\(t\leqslant n\)\(0\leqslant g,q\leqslant10^9\)\(0\leqslant\text{每条边的长度}\leqslant l_i\leqslant10^9\)

Solution

比较好想的一道 \(\texttt{dijkstra}\) 裸题。

为什么呢?

首先我们来看一下题目,发现这和纯 \(\texttt{dijkstra}\) 的唯一的区别是特判——特判积雪厚度。

那特判积雪厚度呢?

这很好办,设从\(s\)点到\(i\)点的最短路径长度为 \(dis_i\),则不能通过 \(i\) 点的特判为:\(dis_i\times q+h_i>l_i\)

所以,这道题目思路一下子就出来了——

  1. 跑一遍 \(\texttt{dijkstra}\),记录下从 \(s\) 到各个点的最短距离(用 \(\texttt{dijkstra}\) 非常好办)。

  2. 从点 \(1\)\(n\)(不包含 \(s\)\(t\))判断上面的特判是否成立,成立的话封掉这个点。

  3. 做完操作 \(2\) 后再跑一遍 \(\texttt{dijkstra}\),求出最终的最短路径。判断是否超过 \(g\)

思路打通了之后,这道题目就不再难了。接下来就是将上面的操作用代码实现的问题了,在此不做赘述。

Code

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

int n, m, s, t, g, q, h[1000007], cnt, dis[100007], vis[100007], del[100007];
struct edge {
	int v, to, nxt;
}e[1000007];
struct node {
	int hi, li;
}a[100007];

inline void a_e(int u, int v, int w) {
	e[++cnt] = (edge){w, v, h[u]}; h[u] = cnt;
	e[++cnt] = (edge){w, u, h[v]}; h[v] = cnt;
}

inline void dj(int s, int t) {
	memset(dis, 0x3f, sizeof(dis));
	memset(vis, 0, sizeof(vis));
	priority_queue<pair<int, int> > q;
	q.push(make_pair(0, s));
	dis[s] = 0;
	while(!q.empty()) {
		int x = q.top().second; q.pop();
		if(vis[x])	continue;
		vis[x] = 1;
		for(int i = h[x]; i; i = e[i].nxt) {
			int y = e[i].to, z = e[i].v;
			if(del[y])	continue;
			if(dis[y] > dis[x] + z) {
				dis[y] = dis[x] + z;
				q.push(make_pair(-dis[y], y));
			}
		}
	}
}

int main() {
	scanf("%d%d%d%d%d%d", &n, &m, &s, &t, &g, &q);
	for(int i = 1; i <= n; ++i)	scanf("%d%d", &a[i].hi, &a[i].li);
	for(int i = 1; i <= m; ++i) {
		int x, y, z;
		scanf("%d%d%d", &x, &y, &z);
		a_e(x, y, z);
	}
	dj(s, t);
	for(int i = 1; i <= n; ++i) {
		if(i == s || i == t)	continue;
		if(dis[i] * q + a[i].hi > a[i].li)	del[i] = 1;
	}
	dj(s, t);
//	printf("%d\n", dis[t]);
	if(dis[t] > g)	printf("wtnap wa kotori no oyatsu desu!");
	else	printf("%d", dis[t]);
	return 0;
}
posted @ 2021-12-23 20:47  Eason_AC  阅读(45)  评论(0)    收藏  举报