bzoj#2095. [Poi2010]Bridges(二分+混合图欧拉回路)
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);
}
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址