2011 Multi-University Training Contest 1 - Cat VS Dog

二分匹配的问题很是迷人,关键点就是在怎样建图。这道题我没有想出来但是学习到了不少的东西。首先匈牙利算法的在main()里面的循环是循环的是left这边的。而find函数这是right。看来我还是没能理解怎样在增广。其次就是建图的问题,如何连边?就是将有冲突的点连接起来。这道题我用的是喜欢猫的小孩在左边,喜欢狗的在右边的方式,进行构图。其实也可以两边都是p个小孩。但是在最后找到最大匹配的时候需要/2。最后就是几个二分图不得不说的公式:1.图G的最大团=其补图的最大独立集    2.最大独立集+最小覆盖集=V

3.最小覆盖集=最大匹配;(最大团:图G的顶点的子集,设D是最大团,则D中任意两点相邻。若u,v是最大团,则u,v有边相连,其补图u,v没有边相连,所以图G的最大团=其补图的最大独立集)

上代码:

#include<cstdio>

#include<cstring>

using namespace std;

struct node{

         intlnum;

         inthnum;

};

int g[510][510],ans,l,r;

bool y[600];

int link[600],p;

bool find(int v){

         inti;

         for(i=1;i<=r-1;i++){

         if(g[v][i]&&!y[i]){

                   y[i]=true;

                   if(link[i]==0|| find(link[i])){

                            link[i]=v;

                            returntrue;

                   }

         }

         }

         returnfalse;

 

}

 

main(){

         intn,m,i,j,num1,num2;

         nodeleft[510],right[510];

         charlike,hate;

         while(scanf("%d%d%d",&n,&m,&p)!=-1){

                   l=1;r=1;

                   for(i=1;i<=p;i++){

                            getchar();

                            scanf("%c%d%c%d",&like,&num1,&hate,&num2);

                   //      printf("\n");

                   //      printf("%c%d%c%d\n",like,num1,hate,num2);

                            if(like=='C'){

                                     left[l].lnum=num1;

                                     left[l++].hnum=num2;

                            }

                            else{

                                     right[r].lnum=num1;

                                     right[r++].hnum=num2;

                            }

                   }

                   memset(g,0,sizeof(g));

                   for(i=1;i<=l-1;i++){

                            for(j=1;j<=r-1;j++){

                                     if(left[i].lnum==right[j].hnum|| left[i].hnum==right[j].lnum)

                                     g[i][j]=1;

                            }

                   }

                   ans=0;

                   memset(link,0,sizeof(link));

                   for(i=1;i<=l-1;i++){

                   memset(y,0,sizeof(y));

                   if(find(i))ans++;

         }

                   printf("%d\n",p-ans);

         }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值