圆桌问题

来源:互联网 发布:2016coc双王升级数据 编辑:程序博客网 时间:2024/04/30 01:31

圆桌问题

题目描述


输入格式 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#includeusing 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;elsech=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<>m>>n;for(int i=1;i<=m;i++){cin>>r[i];peo+=r[i];}for(int i=m+1;i<=n+m;i++)cin>>c[i];memset(head,-1,sizeof(head));s=0,t=n+m+1;for(int i=1;i<=m;i++){add(s,i,r[i],0);add(i,s,0,1);}for(int i=m+1;i<=n+m;i++){add(i,t,c[i],0);add(t,i,0,1);}for(int i=1;i<=m;i++){for(int j=m+1;j<=n+m;j++){add(i,j,1,0);add(j,i,0,1);}}while(1){memset(v,0,sizeof(v));int res=dfs(s,INF);if(res==0)break;ans+=res;}if(ans==peo)putout();elsecout<<0<

原创粉丝点击