1. 程式人生 > 實用技巧 >bzoj#2095. [Poi2010]Bridges(二分+混合圖歐拉回路)

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);
	}
}