网络流24题之圆桌问题

P3254 圆桌问题 

题目描述

假设有来自m 个不同单位的代表参加一次国际会议。每个单位的代表数分别为ri (i =1,2,……,m)。

会议餐厅共有n 张餐桌,每张餐桌可容纳ci (i =1,2,……,n)个代表就餐。

为了使代表们充分交流,希望从同一个单位来的代表不在同一个餐桌就餐。试设计一个算法,给出满足要求的代表就餐方案。

对于给定的代表数和餐桌数以及餐桌容量,编程计算满足要求的代表就餐方案。

输入格式:

第1 行有2 个正整数m 和n,m 表示单位数,n 表示餐桌数,1<=m<=150, 1<=n<=270。

第2 行有m 个正整数,分别表示每个单位的代表数。

第3 行有n 个正整数,分别表示每个餐桌的容量。

输出格式:

如果问题有解,第1 行输出1,否则输出0。接下来的m 行给出每个单位代表的就餐桌号。如果有多个满足要求的方案,只要输出1 个方案。

样例输入:

4 5
4 5 3 5
3 5 2 6 4

样例输出:

1
1 2 4 5
1 2 3 4 5
2 4 5
1 2 3 4 5

本题可以用贪心求解。

首先将桌子从大到小排个序,再讲单位的规模从大到小排个序。单位规模越大就越难满足,所以我们优先考虑单位。

之后先坐大桌子,再坐小桌子就OK了。

但是此题我写的网络流

模型很简单,二分图最大匹配,桌子和单位匹配一下。

建立二分图,每个单位为X集合中的顶点,每个餐桌为Y集合中的顶点,增设附加源S和汇T。

1、从S向每个Xi顶点连接一条容量为该单位人数的有向边。
2、从每个Yi顶点向T连接一条容量为该餐桌容量的有向边。
3、X集合中每个顶点向Y集合中每个顶点连接一条容量为1的有向边。

之后跑最大流。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
#define N 4000000
int n,m;
int a[N];
int b[N];
int nex[N];
int head[N];
int to[N];
int val[N];
int dep[N];
int S,T;
int idx=1;
void addedge(int a,int b,int c)
{
    nex[++idx]=head[a];
    head[a]=idx;
    to[idx]=b;
    val[idx]=c;
}
bool bfs(int S,int T)
{
    memset(dep,-1,sizeof(dep));
    queue <int > q;
    q.push(S);
    dep[S]=0;
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=head[x];i;i=nex[i])
        {
            if(val[i]&&dep[to[i]]==-1)
            {
                dep[to[i]]=dep[x]+1;
                q.push(to[i]);
                if(to[i]==T)
                    return 1;
            }
        }
    }
    return 0;
}
int dinic(int x,int flow)
{
    int nowflow=flow;
    if(x==T)
        return nowflow;
    for(int i=head[x];i;i=nex[i])
    {
        if(val[i]>0&&dep[to[i]]==dep[x]+1)
        {
            int now=dinic(to[i],min(nowflow,val[i]));
            if(now==0)
                dep[to[i]]=-1;
            nowflow-=now;
            val[i]-=now;
            val[i^1]+=now;
            if(nowflow==0)
                break;
        }
    }
    return flow-nowflow;
}
int main()
{
    scanf("%d%d",&n,&m);
    S=0;
    T=n+m+1;
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        sum+=a[i];
        addedge(S,i,a[i]);
        addedge(i,S,0);
    }
    for(int i=n+1;i<=m+n;i++)
    {	
        scanf("%d",&b[i]);
        addedge(i,T,b[i]);
        addedge(T,i,0);
    }
    for(int i=1;i<=n;i++)
        for(int j=n+1;j<=m+n;j++)
        {
            addedge(i,j,1);
            addedge(j,i,0);
        }
    int ans=0;
    while(bfs(S,T))
        ans+=dinic(S,1<<30);
    if(ans==0||ans<sum)
        printf("0");
    else
    {
        puts("1");
        for(int i=1;i<=n;i++)
        {
            for(int j=head[i];j;j=nex[j])
            {
                if(to[j]!=S&&(!val[j]))
                    printf("%d ",to[j]-n);
            }
            puts("");
        }
    }
}
原文地址:https://www.cnblogs.com/342zhuyongqi/p/9813762.html