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\)。
所以,这道题目思路一下子就出来了——
-
跑一遍 \(\texttt{dijkstra}\),记录下从 \(s\) 到各个点的最短距离(用 \(\texttt{dijkstra}\) 非常好办)。
-
从点 \(1\) 到 \(n\)(不包含 \(s\) 和 \(t\))判断上面的特判是否成立,成立的话封掉这个点。
-
做完操作 \(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;
}

浙公网安备 33010602011771号