bzoj#2095. [Poi2010]Bridges(二分+混合圖歐拉回路)
阿新 • • 發佈:2020-08-06
https://darkbzoj.tk/problem/2095
https://blog.csdn.net/commonc/article/details/52442882
題解:
pty說做過,但我不知道什麼做過。
考慮二分答案,問題轉換這個:
有一些有向邊和無向邊,你要給無向邊定向,使得每個點入度=出度;
考慮先給無向邊隨便定向,每條邊可以反悔,記錄\(du[i]\)為\(i\)的入度-出度,然後利用網路流去做最大流即可。
Code:
#include<bits/stdc++.h> #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++) #define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++) #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --) #define ll long long #define pp printf #define hh pp("\n") using namespace std; const int N = 2005; int n, m; struct nod { int a, b, c, d; } a[N]; const int M = 1e6 + 5; int fi[M], to[M], nt[M], r[M], tot = 1; void link(int x, int y, int z) { nt[++ tot] = fi[x], to[tot] = y, r[tot] = z, fi[x] = tot; nt[++ tot] = fi[y], to[tot] = x, r[tot] = 0, fi[y] = tot; } int S, T; int dis[M], d[M], d0, cur[M]; const int inf = 1e9; int du[N]; int bfs() { fo(i, 1, T) dis[i] = inf, cur[i] = fi[i]; dis[S] = 0; d[d0 = 1] = S; for(int i = 1; i <= d0; i ++) { int x = d[i]; for(int j = fi[x]; j; j = nt[j]) if(r[j]) { int y = to[j]; if(dis[y] == inf) dis[y] = dis[x] + 1, d[++ d0] = y; } } return dis[T] < inf; } int dg(int x, int flow) { if(x == T) return flow; int use = 0; for(int &i = cur[x]; i; i = nt[i]) if(r[i] && dis[x] + 1 == dis[to[i]]) { int y = to[i]; int t = dg(y, min(flow - use, r[i])); r[i] -= t, r[i ^ 1] += t, use += t; if(use == flow) return use; } return use; } void cle() { fo(i, 1, T) fi[i] = 0; tot = 1; } int pd(int mi) { cle(); S = n + 1, T = n + 2; fo(i, 1, n) du[i] = 0; fo(i, 1, m) { int c1 = a[i].c <= mi, c2 = a[i].d <= mi; if(!c1 && !c2) return 0; if(c1 && c2) { du[a[i].a] --; du[a[i].b] ++; link(a[i].a, a[i].b, 1); continue; } if(c1) { du[a[i].a] --; du[a[i].b] ++; } else { du[a[i].a] ++; du[a[i].b] --; } } int sumr = 0; fo(i, 1, n) { if(du[i] & 1) return 0; if(du[i] < 0) { link(S, i, -du[i] / 2); sumr += -du[i] / 2; } if(du[i] > 0) { link(i, T, du[i] / 2); } } int ans = 0; while(bfs()) ans += dg(S, inf); return ans == sumr; } int main() { scanf("%d %d", &n, &m); fo(i, 1, m) { scanf("%d %d %d %d", &a[i].a, &a[i].b, &a[i].c, &a[i].d); } int as = -1; for(int l = 0, r = 1000; l <= r; ) { int mi = l + r >> 1; if(pd(mi)) as = mi, r = mi - 1; else l = mi + 1; } if(as == -1) { pp("NIE\n"); } else { pp("%d\n", as); } }