BZOJ 2095 [Poi2010]Bridges (二分+最大流判断混合图的欧拉回路)

题面

n n n个点, m m m条双向边(正向与反向权值不同),求经过最大边权最小的欧拉回路的权值

分析

见 commonc大佬博客

  • 精髓就是通过最大流调整无向边的方向使得所有点的入度等于出度

CODE

#include 
#include 
#include 
using namespace std;
template<typename T>inline void read(T &num) {
    char ch; while((ch=getchar())<'0'||ch>'9');
    for(num=0;ch>='0'&&ch<='9';num=num*10+ch-'0',ch=getchar());
}
const int inf = 1e9;
const int MAXN = 1005;
const int MAXM = 100005;
int n, m, p, fir[MAXN], S, T, tot, cnt, deg[MAXN];
struct edge { int to, nxt, c; }e[MAXM];
inline void add(int u, int v, int cc) {
	e[cnt] = (edge){ v, fir[u], cc }; fir[u] = cnt++;
	e[cnt] = (edge){ u, fir[v], 0 }; fir[v] = cnt++;
}
int dis[MAXN], vis[MAXN], info[MAXN], cur, q[MAXN];
inline bool bfs() {
	int head = 0, tail = 0;
	vis[S] = ++cur; q[tail++] = S;
	while(head < tail) {
		int u = q[head++];
		for(int i = fir[u]; ~i; i = e[i].nxt)
			if(e[i].c && vis[e[i].to] != cur)
				vis[e[i].to] = cur, dis[e[i].to] = dis[u] + 1, q[tail++] = e[i].to;
	}
	if(vis[T] == cur) memcpy(info, fir, (T+1)<<2);
	return vis[T] == cur;
}
int dfs(int u, int Max) {
	if(u == T || !Max) return Max;
	int flow=0, delta;
	for(int &i = info[u]; ~i; i = e[i].nxt)
		if(e[i].c && dis[e[i].to] == dis[u] + 1 && (delta=dfs(e[i].to, min(e[i].c, Max-flow)))) {
			e[i].c -= delta, e[i^1].c += delta, flow += delta;
			if(flow == Max) return flow;
		}
	return flow;
}
inline int dinic() {
	int flow=0, x;
	while(bfs()) {
		while((x=dfs(S, inf))) flow+=x;
	}
	return flow;
}
int A[2005], B[2005], C[2005], D[2005];
inline bool check(int mid) {
	memset(fir, -1, sizeof fir); cnt = 0;
	for(int i = 1; i <= m; ++i) {
		if(C[i] > mid) return 0;
		if(D[i] <= mid)
			add(A[i], B[i], 1);
	}
	int sum = 0;
	for(int i = 1; i <= n; ++i)
		if(deg[i] > 0) add(i, T, deg[i]/2);
		else if(deg[i] < 0) add(S, i, -deg[i]/2), sum -= deg[i]/2;
	return dinic() == sum;
}
int main () {
	read(n), read(m); S = 0; T = n+1;
	for(int i = 1; i <= m; ++i) {
		read(A[i]), read(B[i]), read(C[i]), read(D[i]);
		if(C[i] > D[i]) swap(A[i], B[i]), swap(C[i], D[i]);
		--deg[A[i]], ++deg[B[i]];
	}
	for(int i = 1; i <= n; ++i)
		if(deg[i] % 2) return printf("NIE"), 0;
	int l = 1, r = 1000, mid;
	while(l < r) {
		mid = (l + r) >> 1;
		if(check(mid)) r = mid;
		else l = mid+1;
	}
	printf("%d\n", l);
}

你可能感兴趣的:(网络流,bzoj)