Address
https://www.lydsy.com/JudgeOnline/problem.php?id=1922
Solution
定义状态:
f[u]
f
[
u
]
表示到达并进入城市
u
u
的最短时间。
当然,这个方程是假的,因为自己会间接地转移到自己。
看到既有 max max 又有 min min ,考虑用最短路解决。
这里选择 Dijkstra 。
不过,我们新的定义是:
f[u] f [ u ] 表示到达城市 u u 的最短时间。
表示摧毁城市 u u 结界的最短时间。
算法流程:
(1)每次选出一个没有被保护且 最小的城市 u u 进行扩展。
(2)对于每条边 ,用 max(f[u],g[u])+len<u,v> max ( f [ u ] , g [ u ] ) + l e n < u , v > 更新 f[v] f [ v ] 。
(3)对于每个被 u u 发生器维持结界的城市 ,用 max(f[u],g[u]) max ( f [ u ] , g [ u ] ) 更新 g[v] g [ v ] 。(注:这里的更新是取 max max )
(4) u u 的发生器被摧毁。
(5)以上循环 次。
最后答案 max(f[n],g[n]) max ( f [ n ] , g [ n ] ) 。
Code
// luogu-judger-enable-o2
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Edge(u) for (int e = adj[u], v = go[e]; e; e = nxt[e], v = go[e])
#define Edge2(u) for (int e = adj2[u], v = go2[e]; e; e = nxt2[e], v = go2[e])
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
typedef long long ll; const int N = 3005, M = 7e4 + 5, L = 9e6 + 5;
int n, m, ecnt, nxt[M], adj[N], go[M], val[M], ecnt2, nxt2[L], adj2[N],
go2[L], cnt[N]; ll f1[N], f2[N]; bool mark[N];
void add_edge(int u, int v, int w) {
nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v; val[ecnt] = w;
}
void add_edge2(int u, int v) {
nxt2[++ecnt2] = adj2[u]; adj2[u] = ecnt2; go2[ecnt2] = v;
}
int main() {
int i, j, x, y, z; n = read(); m = read();
For (i, 1, m) x = read(), y = read(), z = read(), add_edge(x, y, z);
For (i, 1, n) {
cnt[i] = read(); For (j, 1, cnt[i]) x = read(), add_edge2(x, i);
}
For (i, 2, n) f1[i] = 1ll << 62; int T = n; while (T--) {
ll mx = 1ll << 62; int p = -1; For (i, 1, n) if (!mark[i] && !cnt[i]
&& max(f1[i], f2[i]) < mx) mx = max(f1[i], f2[i]), p = i;
mark[p] = 1; Edge(p) if (!mark[v]) f1[v] = min(f1[v],
max(f1[p], f2[p]) + val[e]);
Edge2(p) if (!mark[v]) f2[v] = max(f2[v], max(f1[p], f2[p])), cnt[v]--;
}
cout << max(f1[n], f2[n]) << endl; return 0;
}