5.圆桌问题
题目描述 Description
假设有来自m 个不同单位的代表参加一次国际会议。每个单位的代表数分别为
ri
(i=1,2···m), 。会议餐厅共有n张餐桌,每张餐桌可容纳
ci
(i=1,2···n) 个代表就餐。为了使代表们充分交流,希望从同一个单位来的代表不在同一个餐桌就餐。试设计一个算法,给出满足要求的代表就餐方案
输入描述 Input Description
第1行有2个正整数m和n,m表示单位数,n表示餐桌数,1<=m<=150,1<=n<=270。第2行有m个正整数,分别表示每个单位的代表数。文件第3行有n个正整数,分别表示每个餐桌的容量
输出描述 Output Description
将代表就餐方案输出,如果问题有解,在第1行输出1,否则输出0。接下来的m行给出每个单位代表的就餐桌号。如果有多个满足要求的方案,只要输出1个方案
样例输入 Sample Input
4 5
4 5 3 5
3 5 2 6 4
样例输出 Sample Output
1
1 2 4 5
1 2 3 4 5
2 4 5
1 2 3 4 5
分析: 显然,我们将每个单位和每个桌子连一条容量为1的边(每个单位最多只派出一个人)即可满足同单位不在同桌的要求
建图: s向每个单位连一条容量为单位人数的边,每个单位向每个桌子连一条容量为1的边,每个桌子向t连一条容量为桌子能容纳的人数的边
Code:
#include <bits/stdc++.h>
using namespace std;
struct node {
int to;
int next;
int flow;
}e[500*500];
int n,m,tot=1,s,t;
int d[1000],f[1000];
int head[1000],cur[1000];
bool sum[200][300];
int read() {
int ans=0,flag=1;
char ch=getchar();
while( (ch>'9' || ch<'0') && ch!='-' ) ch=getchar();
if(ch=='-') flag=-1,ch=getchar();
while(ch>='0' && ch<='9') ans=ans*10+ch-'0',ch=getchar();
return ans*flag;
}
void addedge(int u,int v,int w) {
e[++tot].to=v;
e[tot].flow=w;
e[tot].next=head[u];
head[u]=tot;
e[++tot].to=u;
e[tot].flow=0;
e[tot].next=head[v];
head[v]=tot;
return ;
}
int dfs(int now,int flow) {
if(now==t)
return flow;
int use=0;
for(int i=cur[now];i;i=e[i].next) {
cur[now]=i;
if(e[i].flow>0 && d[e[i].to]+1==d[now]) {
int temp=dfs(e[i].to,min(flow-use,e[i].flow));
use+=temp;
e[i].flow-=temp;
e[i^1].flow+=temp;
if(flow==use)
return use;
}
}
cur[now]=head[now];
if(!(--f[d[now]]))
d[s]=m+n+2;
++f[++d[now]];
return use;
}
int main() {
n=read(),m=read();
s=0,t=n+m+1;
int ans=0;
for(int i=1;i<=n;i++) {
int w=read();
ans+=w;
addedge(s,i,w);
}
for(int i=n+1;i<=n+m;i++) {
int w=read();
addedge(i,t,w);
}
for(int i=1;i<=n;i++)
for(int j=n+1;j<=n+m;j++)
addedge(i,j,1);
f[0]=n+m+2;
while(d[s]<n+m+2)
ans-=dfs(s,1<<30);
if(!ans) {
printf("1\n");
for(int i=2;i<=tot;i+=2) {
if(e[i].to==s || e[i^1].to==s) continue;
if(e[i].to==t || e[i^1].to==t) continue;
if(!e[i].flow)
sum[e[i^1].to][e[i].to-n]=true;
}
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++)
if(sum[i][j])
printf("%d ",j);
printf("\n");
}
}
else
printf("0");
return 0;
}