题目描述
有来自 (m) 个不同单位的代表参加一次国际会议。第 (i) 个单位派出了 (r_i) 个代表。
会议的餐厅共有 (n) 张餐桌,第 (i) 张餐桌可容纳 (c_i) 个代表就餐。
为了使代表们充分交流,希望从同一个单位来的代表不在同一个餐桌就餐。请给出一个满足要求的方案.
第二道网络流24题 (应该算是比较简单的吧,毕竟自己这种蒟蒻都能想出来),芜湖起飞。
比较好想的二分图多重匹配问题。
我们从源点向每个单位连一条容量为 (r_i) 的边,表示这个单位需要在 (r_i) 张不同的桌子就餐。
在从餐桌向汇点连一条容量为 (c_i) 的边,表示这个餐桌最多能容纳 (c_i) 个人,也就是用来限制最大流的流量。
剩下的就把每个单位和每个餐桌之间连一条容量为 (1) 边,表示这个单位最多可以派一个人到那个餐桌就餐。
我们跑出来的最大流就是满足这样就餐的最多的人数。
无解的情况特判一下就可以。
输出方案的话就在残留网络中找边权为 (0) 的边输出就行。
Code
#include<iostream>
#include<cstdio>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int inf = 2147483647;
const int N = 1010;
int n,m,s,t,ans,sum,x,tot = 1;
int head[N],dep[N];
struct node
{
int to,net,w;
}e[100010];
inline int read()
{
int s = 0, w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
return s * w;
}
void add(int x,int y,int w)
{
e[++tot].w = w;
e[tot].to = y;
e[tot].net = head[x];
head[x] = tot;
}
bool bfs()
{
memset(dep,0,sizeof(dep));
queue<int> q;
q.push(s); dep[s] = 1;
while(!q.empty())
{
int x = q.front(); q.pop();
for(int i = head[x]; i; i = e[i].net)
{
int to = e[i].to;
if(e[i].w && !dep[to])
{
q.push(to);
dep[to] = dep[x] + 1;
if(to == t) return 1;
}
}
}
return 0;
}
int dinic(int x,int flow)
{
if(x == t) return flow;
int rest = flow;
for(int i = head[x]; i; i = e[i].net)
{
int to = e[i].to;
if(e[i].w && dep[to] == dep[x] + 1)
{
int k = dinic(to,min(e[i].w,rest));
if(!k) dep[to] = 0;
e[i].w -= k;
e[i^1].w += k;
rest -= k;
}
}
return flow - rest;
}
int main()
{
n = read(); m = read();
s = 0; t = n+m+1;
for(int i = 1; i <= n; i++)
{
x = read(); sum += x;
add(s,i,x); add(i,s,0);//源点向每个单位连一条边
}
for(int i = 1; i <= m; i++)
{
x = read();
add(n+i,t,x); add(t,n+i,0);//每个桌子向汇点连边
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
add(i,n+j,1); add(n+j,i,0);//单位和餐桌之间互相连边
}
}
int flow = 0;
while(bfs())
{
while(flow = dinic(s,inf)) ans += flow;
}
if(ans < sum)
{
printf("%d
",0);
return 0;
}
printf("%d
",1);
for(int i = 1; i <= n; i++)
{
for(int j = head[i]; j; j = e[j].net)
{
int to = e[j].to;
if(e[j].w == 0) printf("%d ",to-n);
}
printf("
");
}
return 0;
}