(每次到达一个点先补充人的光压,再走) 就等价于 (先走到 n 号点,最后再补充人的光压)。
因为我们求的是到达第 N 个光柱光压最大所需要的最少时间,所以还要加一个
对于 40% 的数据,X=0 的数据,答案就是 dis[n]∗2+E[n]。
考虑 X≠0 的情况。
设 f[u] 表示人到点 u 的最大光压(因为我们是在最后补充人的光压,所以
如果 f[n] 为负,我们要先把它补到 0 再补到最大值,即 先走到 (X - f[n]) + (-f[n]) + (E[n])。
如果 f[n] 为正,说明从未到过 0,那么我们只要计算人走到 (X - f[n]) + (E[n] - f[n])。
所以我们无需分正负讨论,答案都为 E]n]+X−2∗f[n]。
如何计算 f[n] 呢,即计算人的最大光压,显然如果一直走最短路即是最大光压。
Dijstra 注意是大根堆,因为我们是一直减的,这样才能保证正确性。
注意开 ll。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5 + 5;
const ll inf = 1e16;
struct Edge {
int to, next; ll w;
}e[N << 3];
int cnt = 0;
int head[N], vis[N];
void add(int u, int v, ll w) {
e[++ cnt].to = v; e[cnt].w = w; e[cnt].next = head[u]; head[u] = cnt;
}
struct Point {
int id; ll val;
Point(int id, ll val) : id(id), val(val) {}
bool operator < (const Point& a) const {
return val < a.val;
}
};
priority_queue<Point> q;
int n, m;
ll X;
ll f[N], E[N];
void dijstra() {
for (int i = 1; i <= n; i ++) f[i] = inf;
q.push(Point(1, X));
while (!q.empty()) {
Point u = q.top(); q.pop();
if (vis[u.id]) continue;
vis[u.id] = 1;
f[u.id] = u.val;
for (int i = head[u.id]; i; i = e[i].next) {
int v = e[i].to;
q.push(Point(v, min(E[v], f[u.id] - e[i].w)));
}
}
}
int main() {
memset(vis, 0, sizeof(vis));
scanf("%d%d%lld", &n, &m, &X);
for (int i = 1; i <= n; i ++) scanf("%lld", &E[i]);
for (int i = 1; i <= m; i ++) {
int u, v; ll w;
scanf("%d%d%lld", &u, &v, &w);
if (w <= E[u]) add(u, v, w);
if (w <= E[v]) add(v, u, w);
}
dijstra();
if (vis[n]) printf("%lld\n", E[n] + X - 2 * f[n]);
else printf("-1\n");
return 0;
}
本文介绍了一种结合最短路径与光压补充的算法实现,通过Dijkstra算法求解最大光压路径,进而得出达到指定点所需的最少时间和光压补充方案。适用于特定条件下的人或角色能量管理问题。
206

被折叠的 条评论
为什么被折叠?



