«问题描述: 假设有来自m 个不同单位的代表参加一次国际会议。每个单位的代表数分别为 ri(i=1,2,3…m),
。会议餐厅共有n张餐桌,每张餐桌可容纳c i(i=1,2…n) 个代表就餐。
为了使代表们充分交流,希望从同一个单位来的代表不在同一个餐桌就餐。试设计一个算法, 给出满足要求的代表就餐方案。 «编程任务:
对于给定的代表数和餐桌数以及餐桌容量,编程计算满足要求的代表就餐方案。 «数据输入:
由文件roundtable.in提供输入数据。文件第1行有2 个正整数m和n,m表示单位数,n表 示餐桌数,1<=m<=150,
1<=n<=270。文件第2 行有m个正整数,分别表示每个单位的代表 数。文件第3 行有n个正整数,分别表示每个餐桌的容量。 «结果输出:
程序运行结束时,将代表就餐方案输出到文件roundtable.out中。如果问题有解,在文件第 1
行输出1,否则输出0。接下来的m行给出每个单位代表的就餐桌号。如果有多个满足要 求的方案,只要输出1 个方案。
从源点向团体连人数的边,从桌子向汇点连人数的边,每个团体向桌子连1的边,判断是否满流。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int s=448,t=447,oo=0x3f3f3f3f;
int fir[450],ne[200010],to[200010],w[200010],
a[160],b[280],f[450],que[450],
n,m,tot;
void add(int x,int y,int v)
{
tot++;
ne[tot*2]=fir[x];
fir[x]=tot*2;
to[tot*2]=y;
w[tot*2]=v;
ne[tot*2+1]=fir[y];
fir[y]=tot*2+1;
to[tot*2+1]=x;
w[tot*2+1]=0;
}
bool find()
{
int hd,tl,i,u,v;
memset(f,0,sizeof(f));
f[s]=1;
que[1]=s;
hd=tl=1;
while (hd<=tl)
{
u=que[hd++];
for (i=fir[u];i;i=ne[i])
if (w[i]&&!f[v=to[i]])
{
f[v]=f[u]+1;
que[++tl]=v;
}
}
return f[t];
}
int dfs(int u,int lim)
{
int i,v,ret=0,x;
if (u==t) return lim;
for (i=fir[u];i;i=ne[i])
if (w[i]&&f[v=to[i]]==f[u]+1)
{
x=dfs(v,min(lim-ret,w[i]));
w[i]-=x;
w[i^1]+=x;
ret+=x;
}
if (!ret) f[u]=0;
return ret;
}
int main()
{
freopen("roundtable.in","r",stdin);
freopen("roundtable.out","w",stdout);
int i,j,ans=0,x,sum=0;
scanf("%d%d",&m,&n);
for (i=1;i<=m;i++)
scanf("%d",&a[i]),sum+=a[i];
for (i=1;i<=n;i++)
scanf("%d",&b[i]);
for (i=1;i<=m;i++)
add(s,i,a[i]);
for (i=1;i<=n;i++)
add(m+i,t,b[i]);
for (i=1;i<=m;i++)
for (j=1;j<=n;j++)
add(i,m+j,1);
while (find())
while (x=dfs(s,oo))
ans+=x;
if (ans<sum) printf("0\n");
else
{
printf("1\n");
for (i=1;i<=m;i++)
{
for (j=fir[i];j;j=ne[j])
if (!w[j])
printf("%d ",to[j]-m);
putchar('\n');
}
}
}