CF847J

这咋想到网络流的啊。。

最大值最小想到二分最大值,将求解转化为判定。

然后假设当前 check 的值为 \(x\),从源点向每个点连一条容量为 \(x\) 的边,表示这个点至多送出 \(x\) 个礼物。

然后把每个关系也看成一个点,假设当前是第 \(i\) 条关系 \((a_i,b_i)\),那么 \(a_i\)\(b_i\) 都向 \(i^{′}\) 连一条容量为 \(1\) 的边,\(i^{′}\) 向汇点连一条容量为 \(1\) 的边,代表要么 \(a_i\to b_i\),要么 \(b_i\to a_i\)

然后判定就是看有没有满流。

具体细节看代码。

Code:

#include <bits/stdc++.h>
using namespace std;
const int N = 10005, M = 40005, inf = 0x3f3f3f3f;
int n, m;
int u[N], v[N];
int head[N], now[N], ver[M], wei[M], nxt[M], cnt = 1;
int S, T, dep[N];
int maxflow;
queue <int> q;

void add(int u, int v, int w) {
	ver[++cnt] = v, wei[cnt] = w, nxt[cnt] = head[u], head[u] = cnt;
	ver[++cnt] = u, wei[cnt] = 0, nxt[cnt] = head[v], head[v] = cnt;
}

void init() { memset(head, 0, sizeof head), cnt = 1; }

bool bfs() {
	memset(dep, 0, sizeof dep), dep[S] = 1;
	while (!q.empty()) q.pop(); q.push(S), now[S] = head[S];
	while (!q.empty()) {
		int u = q.front(); q.pop();
		for (int i = head[u]; i; i = nxt[i]) {
			int v = ver[i], w = wei[i];
			if (w && !dep[v]) {
				dep[v] = dep[u] + 1, now[v] = head[v], q.push(v);
				if (v == T) return true;
			}
		}
	}
	return false;
}

int Dinic(int u, int flow) {
	if (u == T) return flow;
	int res = flow;
	for (int &i = now[u]; i; i = nxt[i]) {
		int v = ver[i], w = wei[i];
		if (w && dep[v] == dep[u] + 1) {
			int k = Dinic(v, min(res, w));
			if (!k) dep[v] = 0;
			wei[i] -= k, wei[i ^ 1] += k, res -= k;
		}
		if (!res) break;
	}
	return flow - res;
}

bool check(int k) {
	init();
	for (int i = 1; i <= m; ++i) add(u[i], i + n, 1), add(v[i], i + n, 1), add(i + n, T, 1);
	for (int i = 1; i <= n; ++i) add(S, i, k);
	int ans = 0, flow;
	while (bfs())
		while (flow = Dinic(S, inf)) ans += flow;
	return ans == m;
}

int main() {
	scanf("%d%d", &n, &m), S = 0, T = n + m + 1;
	for (int i = 1; i <= m; ++i) scanf("%d%d", &u[i], &v[i]);
	int l = 0, r = m;
	while (l < r) {
		int mid = l + r >> 1;
		if (check(mid)) r = mid;
		else l = mid + 1;
	}
	printf("%d\n", l);
	check(l);
	for (int i = 1; i <= m; ++i) {
		if (wei[i * 6 - 4]) printf("%d %d\n", v[i], u[i]);
		else printf("%d %d\n", u[i], v[i]);
	}
	return 0;
}
posted @ 2022-10-15 20:03  Kobe303  阅读(20)  评论(0编辑  收藏  举报