[BZOJ1922][Sdoi2010]大陆争霸(Dijkstra)

Address

https://www.lydsy.com/JudgeOnline/problem.php?id=1922

Solution

定义状态:
f [ u ] 表示到达并进入城市 u 的最短时间。

f [ u ] = max ( min < v , u > { f [ v ] + l e n < v , u > } , max v u f [ v ] )

当然,这个方程是假的,因为自己会间接地转移到自己。
看到既有 max 又有 min ,考虑用最短路解决。
这里选择 Dijkstra
不过,我们新的定义是:
f [ u ] 表示到达城市 u 的最短时间。
g [ u ] 表示摧毁城市 u 结界的最短时间。
算法流程:
(1)每次选出一个没有被保护且 max ( f , g ) 最小的城市 u 进行扩展。
(2)对于每条边 < u , v > ,用 max ( f [ u ] , g [ u ] ) + l e n < u , v > 更新 f [ v ]
(3)对于每个被 u 发生器维持结界的城市 v ,用 max ( f [ u ] , g [ u ] ) 更新 g [ v ] 。(注:这里的更新是取 max
(4) u 的发生器被摧毁。
(5)以上循环 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;
}

猜你喜欢

转载自blog.csdn.net/xyz32768/article/details/81132843