洛谷-P3254 圆桌问题
圆桌问题
最大流
建图完就很简单
考虑将单位和餐桌视为点
-
限制每个餐桌上的代表所属的单位不同:只要将单位和餐桌之间的流容量设置为 \(1\)
-
源点对单位有容量为 \(r_i\) 的边,餐桌对汇点有容量为 \(c_i\) 的边
-
最大流如果为 \(\sum_{i=1}^{m}r_i\) 则说明每个人都能上桌
答案的输出只需要找到所有单位流向餐桌的流是走的哪条边就可以
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 1e5 + 10;
const int inf = 1e9 + 10;
int tp = 1, s, t, len;
int cur[maxn], head[maxn], nex[maxn], to[maxn], val[maxn];
int dep[maxn];
void add(int u, int v, int w)
{
tp++;
nex[tp] = head[u];
val[tp] = w;
to[tp] = v;
head[u] = tp;
}
bool bfs()
{
for(int i=0; i<=len; i++) cur[i] = head[i];
for(int i=0; i<=len; i++) dep[i] = 0;
queue<int>q;
q.push(s);
dep[s] = 1;
while(q.size())
{
int now = q.front();
q.pop();
for(int i=head[now]; i; i=nex[i])
{
int u = to[i];
if(val[i] > 0 && dep[u] == 0)
{
dep[u] = dep[now] + 1;
q.push(u);
}
}
}
return dep[t];
}
int dfs(int now, int flow)
{
if(now == t) return flow;
int ans = 0;
for(int i=cur[now]; ans < flow && i; i=nex[i])
{
cur[now] = i;
int u = to[i];
if(val[i] > 0 && dep[u] == dep[now] + 1)
{
int x = dfs(u, min(flow - ans, val[i]));
ans += x;
val[i] -= x;
val[i ^ 1] += x;
}
}
return ans;
}
int dinic()
{
int ans = 0;
while(bfs())
ans += dfs(s, inf);
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, m;
cin >> m >> n;
s = n + m + 1;
t = s + 1;
int sum = 0;
for(int i=1; i<=m; i++)
{
int x;
cin >> x;
add(s, i, x);
add(i, s, 0);
sum += x;
}
for(int i=1; i<=n; i++)
{
int x;
cin >> x;
add(i + m, t, x);
add(t, i + m, x);
}
for(int i=1; i<=m; i++)
{
for(int j=1+m; j<=n+m; j++)
{
add(i, j, 1);
add(j, i, 0);
}
}
len = n + m + 2;
if(dinic() != sum) cout << 0 << endl;
else
{
cout << 1 << endl;
for(int i=1; i<=m; i++)
{
int temp = 0;
for(int j=head[i]; j; j=nex[j])
{
int u = to[j];
if(u != s && val[j] == 0)
{
if(temp++) cout << " ";
cout << u - m;
}
}
cout << endl;
}
}
return 0;
}