1 条题解
-
0
题目理解
我们有一个带权无向图, 个点, 条边。
起点 ,终点 ,要求在 秒内到达。特殊条件:
- 每个点 初始积雪深度 ,雪深限制 。
- 每秒钟雪增加 mm。
- 到达某个点的时间为 秒时,该点雪深为 。
- 如果到达时雪深 ,则无法继续前进(被困住)。
目标:求从 到 的最短时间(秒),如果超过 或无法到达,输出固定字符串。
关键点分析
1. 雪深限制条件
在点 到达时间 必须满足: [ h_i + q \times T \le l_i ] 即: [ T \le \frac{l_i - h_i}{q} \quad (\text{如果 } q > 0) ] 如果 ,则条件简化为 (初始就满足才能进入)。
如果 ,那么每个点 有一个最晚到达时间: [ \text{deadline}[i] = \left\lfloor \frac{l_i - h_i}{q} \right\rfloor ] 如果 ,则 ,表示永远不能到达(一开始雪就超限)。
2. 问题转化
我们要求最短时间 ,同时保证在任意点 的到达时间 。
这相当于在普通 Dijkstra 最短路的基础上,增加了一个时间上限约束。
3. 算法思路
用 Dijkstra 算法求最短时间,但松弛边时要检查:
- 到达下一个点 的时间 是否超过该点的 deadline。
- 如果超过,则不能走这条边。
注意:即使 不超过 deadline[],我们也要正常更新,因为可能更早到达 对后续更有利。
4. 特殊情况处理
- :此时雪不增加,只需初始 的点才能访问。如果初始 ,则 deadline[] = -1。
- :按上面公式计算 deadline。
- 如果 且 ,则 deadline[] = INF(无限大)。
- 如果 ,deadline[] = -1(不可达)。
- 如果 且 ,deadline[] = (下取整)。
5. 复杂度
使用优先队列 Dijkstra,复杂度 ,可以处理 。
代码实现
#include <iostream> #include <vector> #include <queue> #include <algorithm> #include <climits> using namespace std; typedef long long ll; const ll INF = 1e18; struct Edge { int to; ll len; }; struct Node { int id; ll dist; bool operator<(const Node& other) const { return dist > other.dist; } }; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n, m, s, t, g, q; cin >> n >> m >> s >> t >> g >> q; vector<ll> h(n + 1), l(n + 1); for (int i = 1; i <= n; i++) { cin >> h[i] >> l[i]; } vector<vector<Edge>> graph(n + 1); for (int i = 0; i < m; i++) { int u, v, w; cin >> u >> v >> w; graph[u].push_back({v, w}); graph[v].push_back({u, w}); } vector<ll> deadline(n + 1, INF); for (int i = 1; i <= n; i++) { if (l[i] < h[i]) { deadline[i] = -1; } else { if (q == 0) { deadline[i] = INF; } else { deadline[i] = (l[i] - h[i]) / q; } } } vector<ll> dist(n + 1, INF); dist[s] = 0; priority_queue<Node> pq; pq.push({s, 0}); while (!pq.empty()) { Node cur = pq.top(); pq.pop(); int u = cur.id; ll d = cur.dist; if (d != dist[u]) continue; for (const Edge& e : graph[u]) { int v = e.to; ll newTime = d + e.len; if (newTime > deadline[v]) continue; if (newTime < dist[v]) { dist[v] = newTime; pq.push({v, newTime}); } } } if (dist[t] > g) { cout << "wtnap wa kotori no oyatsu desu!\n"; } else { cout << dist[t] << "\n"; } return 0; }
样例验证
样例 1
边:1-2 长度 6计算 deadline:
点1:
点2:从 1 到 2 时间 6 ≤ 7,可以到达。输出 6。
样例 3
点3的 ,,deadline[3] = 0,意味着必须在 0 秒内到达点3,这不可能,所以某些路径被阻断,导致无法到达终点。
总结
这道题本质是带时间约束的最短路,约束是每个点有一个最晚到达时间。
用 Dijkstra 求解时,在松弛边时检查时间约束即可。
注意 和 时 deadline 的计算方式不同,以及数据范围要用long long
。
- 1
信息
- ID
- 3285
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者