圆桌问题

圆桌问题

题目描述


输入格式 2206.in

文件第1行有2个正整数m和n,m表示单位数,n表示餐桌数,1<=m<=150, 1<=n<=270。文件第2行有m个正整数,分别表示每个单位的代表数。文件第3行有n个正整数,分别表示每个餐桌的容量。

输出格式 2206.out

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

输入样例 2206.in

4 5 
4 5 3 5 
3 5 2 6 4

输出样例 2206.out


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

    这题,跟上一题非常地像。它同样是二分图匹配问题。 可以用最大流解决。

    题目中,每个团队只有r[i]个人,每张桌子只能容纳c[i]个人,而且每个人只能坐到特定的桌子上,一个人只能对应一张桌子。我们可以将r[i]、c[i]、1都看做流量的上限,进行构图。其实就是要求,一个流,为一个合法解。

    1.建立源点S,集合A中的结点为团队,集合B中的结点为桌子

    2.S向A集合中每个节点都连一条权值为r[i]的边

    3.A集合中的每个节点都与其能够匹配的桌子连一条权值为1的边。

    (这是因为每个人只能对应一张桌子)

    4.B集合中的每个节点都与汇点T连一条权值为c[i]的边。

    (图片参照飞行员匹配问题,此处不再附)

    上述构图的意义在于: 每一个流,都代表着一个人能够坐到指定的桌子上。

    这样一来,如何判断是否有合法方案呢?就如前文所说,流量1,就代表一个人坐到了合适的位置。因此,如果跑出的最大流等于总人数,这就是合法方案。

    如何输出方案呢?这个问题就很简单了。如果某代表和某圆桌匹配成功,那么它们之间的这条边必定被流过,且是满流。因此,最后遍历从所有A集合的点连到B集合的正向边,如果此时边权为0,则代表满流,输出对应的结点即可。

    做了这几题,发现网络流构图实在是太重要了,不过也很玄学……就目前做的几题最大流来看,似乎就是需要构造出图,使得流为所求,且不能造成重复、与题目的要求相悖。怎么连边、边的权值是多少,都是值得好好考虑的问题。本弱目前参透得还不太深……留坑待补。

    代码如下:

#include
   
   
    
    
#include
    
    
     
     
#include
     
     
      
      
using namespace std;
const int MAXN=600,INF=(1<<29);
int r[MAXN],c[MAXN],v[MAXN],peo,cur,s,t;
int head[MAXN],m,n,ans;
struct yy
{
	int to,next,va,type;
}edge[MAXN*MAXN];
void add(int from,int to,int va,int type)
{
	edge[++cur].to=to;
	edge[cur].next=head[from];
	edge[cur].va=va;
	edge[cur].type=type;
	head[from]=cur;
}
int dfs(int cur,int mina)
{
	if(cur==t)	return mina;
	v[cur]=1;
	int h=head[cur];
	while(h!=-1)
	{
		int to=edge[h].to,va=edge[h].va,ty=edge[h].type,ch;
		if(v[to]==0&&va!=0)
		{
			int res=dfs(to,min(mina,va));
			if(ty==0)	ch=h+1;
			else	ch=h-1;
			if(res!=0)
			{
				edge[h].va-=res;
				edge[ch].va+=res;
				return res;
			}
		}
		h=edge[h].next;
	}
	return 0;
}
void putout()
{
	cout<<1<
      
       

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值