cogs729 圆桌聚餐

«问题描述: 假设有来自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');
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值