題解 BZOJ#4669. 搶奪
阿新 • • 發佈:2021-07-21
為什麼別人一眼二分答案然後就莽過去了,我想半天不知道咋二分。後來發現壓根不需要二分。
可以發現的性質是,我們一定優先走最短路,但是容量有限,一些較長路能夠分流。但是不管怎樣,我們一定走的是最短的若干條路徑。
首先建出費用流的圖,對於一條長為 \(d\) 的最短路以及流量 \(f\),答案為 \(d+(k-f-1)/f+1\)。
而每新加入一條較劣的長為 \(d'\) 最短路,前 \(d\) 時間所有路徑分流,後 \(d'-d\) 的時間會讓之前的最短路儘量多通過人數。
不斷增廣然後取最優答案即可。
#include <bits/stdc++.h> using i64 = long long; const i64 Inf = 0x3f3f3f3f3f3f3f3f; struct Graph { std::vector<int> head; struct Edge { int nxt, to; i64 flow, cost; }; std::vector<Edge> e; Graph(int n) : head(n + 1, -1) {} void add(int u, int v, i64 f, i64 c) { e.emplace_back(Edge{head[u], v, f, c}); head[u] = e.size() - 1; } void add_flow(int u, int v, i64 f, i64 c) { add(u, v, f, c); add(v, u, 0, -c); } }; struct Dinic { Graph &G; std::vector<i64> dis; std::vector<int> cur, inq, vis; Dinic(int n, Graph &G) : G(G), dis(n + 1), cur(n + 1), inq(n + 1), vis(n + 1) {} i64 spfa(int S, int T) { std::fill(dis.begin(), dis.end(), Inf); std::queue<int> q; q.push(S); inq[S] = true; dis[S] = 0; while (!q.empty()) { int u = q.front(); q.pop(); inq[u] = false; for (int i = G.head[u]; ~i; i = G.e[i].nxt) { int v = G.e[i].to; if (G.e[i].flow > 0 && dis[v] > dis[u] + G.e[i].cost) { dis[v] = dis[u] + G.e[i].cost; if (!inq[v]) { q.push(v); inq[v] = true; } } } } return dis[T]; } i64 dfs(int u, i64 lim, int T) { if (!lim || u == T) return lim; i64 rest = lim; vis[u] = true; for (int &i = cur[u]; ~i; i = G.e[i].nxt) { int v = G.e[i].to; if (G.e[i].flow > 0 && dis[v] == dis[u] + G.e[i].cost && !vis[v]) { i64 rlow = dfs(v, std::min(rest, (i64) G.e[i].flow), T); if (!rlow) dis[v] = Inf; G.e[i].flow -= rlow; G.e[i ^ 1].flow += rlow; rest -= rlow; if (!rest) break; } } vis[u] = false; return lim - rest; } i64 solve(int S, int T, i64 k) { i64 lastd = 0; i64 ans = Inf; i64 sumf = 0; while (k > 0) { i64 maxd = spfa(S, T); if (maxd == Inf) break; i64 flow = 0; i64 rlow; std::copy(G.head.begin(), G.head.end(), cur.begin()); while (rlow = dfs(S, Inf, T), rlow > 0) flow += rlow; // std::cerr << maxd << ' ' << flow << '\n'; k -= flow + (maxd - lastd) * sumf; sumf += flow; ans = std::min(ans, maxd + (k - 1) / sumf + 1); lastd = maxd; } return ans; } }; int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int n, m, k; while (std::cin >> n >> m >> k) { Graph G(n); for (int i = 0; i < m; ++i) { int u, v, w; std::cin >> u >> v >> w; ++u; ++v; G.add_flow(u, v, w, 1); } if (k == 0) { std::cout << 0 << '\n'; continue; } i64 ans = Dinic(n, G).solve(1, n, k); if (ans == Inf) std::cout << "No solution" << '\n'; else std::cout << ans << '\n'; } return 0; }