「POI2010」Bridges

传送门
Luogu团队题链接

解题思路

首先二分答案,然后在所有边权小于二分值的边和所有点组成的图中判欧拉回路。
由于可能出现混合图,所以要用到网络流。
把所有无向边钦定一个方向,那么原图就是一个有向图。
那么存在欧拉回路的充要条件就所有点的入度等于出度且图联通。
我们考虑把点 \(x\) 的入度与出度之差记作 \(\Delta x\)
那么对于所有的定向后的无向边 \((u,v)\),连一条从 \(u\rightarrow v\) 的容量为 \(1\) 的边。
表示将该条边反向可以使 \(\Delta u += 2,\Delta v -= 2\)
然后考虑对于所有度数差小于 \(0\) 的点 \(x\),连一条 \(s \rightarrow x\) 的容量为 \(\frac{|\Delta x|}{2}\) 的边。
表示 \(x\) 需要操作这么多次,使得 \(\Delta x\) 达到 \(0\)。小于零的情况同理。
最后判断是否满流即可。

细节注意事项

  • 细节有点多,要有耐心

参考代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <ctime>
#include <queue>
#define rg register
using namespace std;
template < typename T > inline void read(T& s) {
	s = 0; int f = 0; char c = getchar();
	while (!isdigit(c)) f |= (c == '-'), c = getchar();
	while (isdigit(c)) s = s * 10 + (c ^ 48), c = getchar();
	s = f ? -s : s;
}

const int _ = 1010;
const int __ = 5010 * 2 + 1010 * 2;
const int INF = 2147483647;

int tot = 1, head[_], nxt[__], ver[__], cap[__];
inline void Add_edge(int u, int v, int d)
{ nxt[++tot] = head[u], head[u] = tot, ver[tot] = v, cap[tot] = d; }
inline void link(int u, int v, int d) { Add_edge(u, v, d), Add_edge(v, u, 0); }

int n, m, s, t, liu, dgr[_], dep[_];
struct node{ int a, b, c, d; }g[__];

inline int bfs() {
	static queue < int > Q;
	memset(dep, 0, sizeof dep);
	dep[s] = 1, Q.push(s);
	while (!Q.empty()) {
		int u = Q.front(); Q.pop();
		for (rg int i = head[u]; i; i = nxt[i]) {
			int v = ver[i];
			if (dep[v] == 0 && cap[i] > 0)
				dep[v] = dep[u] + 1, Q.push(v);
		}
	}
	return dep[t] > 0;
}

inline int dfs(int u, int flow) {
	if (u == t) return flow;
	for (rg int i = head[u]; i; i = nxt[i]) {
		int v = ver[i];
		if (dep[v] == dep[u] + 1 && cap[i] > 0) {
			int res = dfs(v, min(flow, cap[i]));
			if (res) { cap[i] -= res, cap[i ^ 1] += res; return res; }
		}
	}
	return 0;
}

inline int Dinic() {
	int res = 0;
	while (bfs()) while (int d = dfs(s, INF)) res += d;
	return res;
}

inline bool check(int mid) {
	s = 0, t = n + 1;
	tot = 1, memset(head, 0, sizeof head);
	for (rg int i = 1; i <= m; ++i) {
		if (g[i].c > mid) return 0;
		if (g[i].d <= mid) link(g[i].a, g[i].b, 1);
	}
	for (rg int i = 1; i <= n; ++i) {
		if (dgr[i] < 0) link(s, i, -dgr[i] / 2);
		if (dgr[i] > 0) link(i, t, dgr[i] / 2);
	}
	return Dinic() == liu / 2;
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
#endif
	read(n), read(m);
	for (rg int i = 1; i <= m; ++i) {
		read(g[i].a), read(g[i].b), read(g[i].c), read(g[i].d);
		if (g[i].c > g[i].d)
			swap(g[i].a, g[i].b), swap(g[i].c, g[i].d);
		--dgr[g[i].a], ++dgr[g[i].b];
	}
	for (rg int i = 1; i <= n; ++i) {
		if (dgr[i] % 2 != 0) return puts("NIE"), 0;
		liu += abs(dgr[i]) / 2;
	}
	int l = 1, r = 1000;
	while (l < r) {
		int mid = (l + r) >> 1;
		if (check(mid)) r = mid;
		else l = mid + 1;
	}
	printf("%d\n", l);
	return 0;
}

完结撒花 \(qwq\)

posted @ 2019-10-26 22:04  Sangber  阅读(207)  评论(0编辑  收藏  举报