UVA-3231 Fair Share 二分流量
题面
链接:https://vjudge.net/problem/UVALive-3231
题意
给定n个机器,m个工作,每个工作可以给两个机器中的某一个做,问每台机器做的工作的最大值最小是多少
题解
网络流
首先源点向每个工作连一条容量为1的边,代表每个工作只能被做一次,然后每个工作向机器连边,容量为1,每个机器向汇点怎么连边呢?为了让每个机器做的工作量最大值最小,我们可以二分答案,机器向汇点连边,容量为二分的值,如果满流,说明每个工作都有人做,可以继续减小,最小值就是答案
代码
#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 20050;
struct node {
int v, cap, nxt;
node () {}
node (int v, int cap, int nxt): v(v), cap(cap), nxt(nxt) {}
} edge[N * 100];
int head[N], tot;
void init() {
memset(head, -1, sizeof(head));
tot = 0;
}
int dep[N];
void adde(int u, int v, int w) {
edge[tot] = node(v, w, head[u]);
head[u] = tot++;
edge[tot] = node(u, 0, head[v]);
head[v] = tot++;
}
int cur[N];
int gap[N];
int pre[N];
int sap(int s, int t, int n) {
memset(dep, 0, sizeof(dep));
memset(gap, 0, sizeof(gap));
memcpy(cur, head, sizeof(head));
memset(pre, 0, sizeof(pre));
gap[0] = n;
int u = s;
pre[u] = -1;
int ans = 0;
while (dep[s] < n) {
if (u == t) {
int minn = inf;
for (int i = pre[u]; ~i; i = pre[edge[i ^ 1].v]) {
if (minn > edge[i].cap) minn = edge[i].cap;
}
for (int i = pre[u]; ~i; i = pre[edge[i ^ 1].v]) {
edge[i].cap -= minn;
edge[i ^ 1].cap += minn;
}
u = s;
ans += minn;
continue;
}
bool flag = false;
int v;
for (int i = cur[u]; ~i; i = edge[i].nxt) {
v = edge[i].v;
if (edge[i].cap && dep[v] + 1 == dep[u]) {
flag = true;
cur[u] = pre[v] = i;
break;
}
}
if (flag) {
u = v;
continue;
}
int minn = n;
for (int i = head[u]; ~i; i = edge[i].nxt) {
if (edge[i].cap && dep[edge[i].v] < minn) {
minn = dep[edge[i].v];
cur[u] = i;
}
}
gap[dep[u]]--;
if (!gap[dep[u]]) return ans;
dep[u] = minn + 1;
gap[dep[u]]++;
if (u != s) u = edge[pre[u] ^ 1].v;
}
return ans;
}
int a[N], b[N];
int main () {
int cse;
scanf("%d", &cse);
while (cse--) {
init();
int n, m;
scanf("%d%d", &n, &m);
int s = 0, t = n + m + 1;
for (int i = 1; i <= m; i++) {
scanf("%d%d", &a[i], &b[i]);
}
int l = 0, r = 20000;
int ans = inf;
while (l <= r) {
int mid = (l + r) >> 1;
init();
for (int i = 1; i <= m; i++) {
adde(i, a[i] + m, 1);
adde(i, b[i] + m, 1);
adde(s, i, 1);
}
for (int i = 1; i <= n; i++) {
adde(i + m, t, mid);
}
int now = sap(s, t, n + m + 2);
if (now == m) {
ans = min(ans, mid);
r = mid - 1;
}
else l = mid + 1;
}
printf("%d\n", ans);
}
return 0;
}