[洛谷P1401]城市
题目大意:有$n(2\leqslant n\leqslant200)$个城市,$m(1\leqslant m\leqslant40000)$条无向边,你要找$T(1\leqslant T\leqslant200)$条从城市$1$到城市$n$的路,使得最长的边的长度最小,边不能重复用。
题解:二分答案,跑网络流,每条边边权为$1$,看最大流是否比$T$大。(实测我常数不能再大的$HLPP$跑的比$ISAP$慢,所以就放$ISAP$了,其实都是板子)
卡点:无
C++ Code:
#include <cstdio> #include <cstring> #include <vector> #include <queue> #define maxn 210 #define maxm 40010 const int inf = 0x3f3f3f3f; inline int min(int a, int b) {return a < b ? a : b;} inline int max(int a, int b) {return a > b ? a : b;} namespace Network_Flow { int st, ed, MF, n; int head[maxn], cnt = 2; struct Edge { int to, nxt, w; } e[maxm << 1]; inline void addE(int a, int b, int c) { e[cnt] = (Edge) {b, head[a], c}; head[a] = cnt; e[cnt ^ 1] = (Edge) {a, head[b], c}; head[b] = cnt ^ 1; cnt += 2; } int GAP[maxn], d[maxn]; int last[maxn]; int q[maxn], h, t; inline void init() { GAP[d[ed] = 1] = 1; for (int i = 1; i <= n; i++) last[i] = head[i]; q[h = t = 0] = ed; while (h <= t) { int u = q[h++]; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (!d[v]) { d[v] = d[u] + 1; GAP[d[v]]++; q[++t] = v; } } } } int dfs(int u, int low) { if (!low || u == ed) return low; int w, res = 0; for (int &i = last[u]; i; i = e[i].nxt) { int v = e[i].to; if (d[u] == d[v] + 1) { w = dfs(v, min(low, e[i].w)); res += w, low -= w; e[i].w -= w, e[i ^ 1].w += w; if (!low) return res; } } if (!(--GAP[d[u]])) d[st] = n + 1; ++GAP[++d[u]], last[u] = head[u]; return res; } inline void ISAP(int S, int T) { st = S, ed = T; init(); while (d[st] <= n) MF += dfs(st, inf); } inline void clear() { memset(head, 0, sizeof head); cnt = 2; memset(GAP, 0, sizeof GAP); memset(d, 0, sizeof d); MF = 0; } } #define read() R::READ() #include <cctype> namespace R { int x; #ifdef ONLINE_JUGER #define M 1 << 25 char op[M], *ch; inline void init() {fread(ch = op, 1, M, stdin);} inline int READ() { while (isspace(*ch)) ch++; for (x = *ch & 15, ch++; isdigit(*ch); ch++) x = x * 10 + (*ch & 15); return x; } #undef M #else char ch; inline int READ() { ch = getchar(); while (isspace(ch)) ch = getchar(); for (x = ch & 15, ch = getchar(); isdigit(ch); ch = getchar()) x = x * 10 + (ch & 15); return x; } #endif } int n, m, T, M; int u[maxm], v[maxm], w[maxm]; inline bool check(int mid) { for (int i = 1; i <= m; i++) if (w[i] <= mid) Network_Flow::addE(u[i], v[i], 1); Network_Flow::ISAP(1, n); if (Network_Flow::MF >= T) return true; return false; } int main() { #ifdef ONLINE_JUGER R::init(); #endif n = read(), m = read(), T = read(); Network_Flow::n = n; for (int i = 1; i <= m; i++) { u[i] = read(), v[i] = read(), w[i] = read(); M = max(M, w[i]); } int l = 1, r = M, ans = -1; while (l <= r) { int mid = l + r >> 1; if (check(mid)) { r = mid - 1; ans = mid; } else l = mid + 1; if (l <= r) Network_Flow::clear(); } printf("%d\n", ans); return 0; }