网络流24题-圆桌问题

圆桌问题

时空限制1000ms / 128MB

题目描述

假设有来自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

二分图多重最大匹配。
参考博客:https://blog.csdn.net/luozhong11/article/details/52430572

在二分图最大匹配中,每个点(不管是X点还是Y点)最多只能和一条匹配边相关联,然而,我们经常遇到这种问题,即二分图匹配中一个点可以和多条匹配边相关联,但有上限,或者说,Li表示点i最多可以和多少条匹配边相关联。

二分图多重匹配分为二分图多重最大匹配与二分图多重最优匹配两种,分别可以用最大流与最大费用最大流解决。

(1)二分图多重最大匹配:
在原图上建立源点S和汇点T,S向每个X点连一条容量为该X点L值的边,每个Y点向T连一条容量为该Y点L值的边,原来二分图中各边在新的网络中仍存在,容量为1(若该边可以使用多次则容量大于1),求该网络的最大流,就是该二分图多重最大匹配的值。

(2)二分图多重最优匹配:
在原图上建立源点S和汇点T,S向每个X点连一条容量为该X点L值、费用为0的边,每个Y点向T连一条容量为该Y点L值、费用为0的边,原来二分图中各边在新的网络中仍存在,容量为1(若该边可以使用多次则容量大于1),费用为该边的权值。求该网络的最大费用最大流,就是该二分图多重最优匹配的值。

#include<bits/stdc++.h>
#define N 520
using namespace std;
typedef struct
{
    int v;
    long long flow;
}ss;

ss edg[N*N];
vector<int>edges[N];
int now_edges=0;
long long fl[N][N]={0};

void addedge(int u,int v,long long flow)
{
    fl[u][v]+=flow;
    edges[u].push_back(now_edges);
    edg[now_edges++]=(ss){v,flow};
    edges[v].push_back(now_edges);
    edg[now_edges++]=(ss){u,0};
}

int dis[N],S,T;
bool bfs()
{
    memset(dis,0,sizeof(dis));
    queue<int>q;
    q.push(S);
    dis[S]=1;
    
    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        int Size=edges[now].size();
        
        for(int i=0;i<Size;i++)
        {
            ss e=edg[edges[now][i]];
            if(e.flow>0&&dis[e.v]==0)
            {
                dis[e.v]=dis[now]+1;
                q.push(e.v);
            }
        }
    }    
    if(dis[T]==0)return 0;
    return 1;
    
}
int current[N];
long long dfs(int now,long long maxflow)
{
    if(now==T)return maxflow;
    int Size=edges[now].size();
    for(int i=current[now];i<Size;i++)
    {
        current[now]=i;
        ss &e=edg[edges[now][i]];
        
        if(e.flow>0&&dis[e.v]==dis[now]+1)
        {
            long long Flow=dfs(e.v,min(maxflow,e.flow));
            
            if(Flow)
            {
                fl[now][e.v]-=Flow;
                fl[e.v][now]+=Flow;
                
                e.flow-=Flow;
                edg[edges[now][i]^1].flow+=Flow;
                return Flow;
            }
        }
    }
    return 0;
}

long long dinic()
{
    long long ans=0,flow;
    while(bfs())
    {
        memset(current,0,sizeof(current));
        while(flow=dfs(S,LLONG_MAX/2))ans+=flow;
    }
    return ans;
}

int main()
{
    int m,n;
    long long sum=0;
    int present[N],desk[N];
    scanf("%d %d",&m,&n);
    for(int i=1;i<=m;i++)scanf("%d",&present[i]),sum+=present[i];
    for(int i=1;i<=n;i++)scanf("%d",&desk[i]);
    
    S=n+m+1;
    T=n+m+2;

    for(int i=1;i<=m;i++)addedge(S,i,present[i]);
    for(int i=1;i<=n;i++)addedge(i+m,T,desk[i]);

    for(int i=1;i<=m;i++)
    for(int j=1;j<=n;j++)
    addedge(i,j+m,1);
    
    long long ans=dinic();
    
    if(sum==ans)
    {
        printf("1\n");
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=n;j++)
            if(fl[j+m][i])printf("%d ",j);
            printf("\n");
        }
    }
    else
    printf("0\n");
    return 0;
    
}
View Code

 

posted @ 2018-08-25 00:52  1371767389  阅读(137)  评论(0编辑  收藏  举报