匈牙利算法(二分图匹配)

好,来讲简单的东西了

匈牙利算法

也就是二分图匹配

Q二分图匹配是什么?

还是先看题比较好
公牛和母牛
【问题描述】
有n只公牛和m只母牛,然后每只公牛都能和几只的母牛配对。在每只公牛只能配对一只母牛的情况下,求能为牛们配对最多多少对?
【输入】
第一行两个整数,n (0 ≤ n ≤ 400) 和 m (0 ≤ m ≤ 500) 。
第二行到第N+1行一共N行,每行对应一只公牛。第一个数字 (si) 是这头公牛有匹配关系的母牛的数目 (0 ≤ si ≤ m) 。后面的si个数表示这些母牛编号。母牛编号限定在区间 (1..m) 中。
【输出】
输出一个整数,表示最多能配对成功多少头牛?

A:所谓二分图就是像这道题说的那样
让公牛排一列,母牛排一列
给可以匹配的公牛母牛连一条线
然后来匹配…问最多能匹配上多少公牛?

先看思路
1. 从第一只公牛开始遍历每一只母牛,直到找到一只他可以配对的母牛;
2. 如果这只母牛没有配对过,那么配对成功,返回1,下一只公牛继续配对。
3. 如果这只母牛已经配对过了怎么办?
我们称正在配对的这只公牛为A,这只母牛已经配对的公牛为B。这时,让公牛B去进行步骤1,但是要从这只母牛开始往后问(因为前面的母牛他在配对的时候已经问过了),看看能否找到另一只母牛也能与之配对。

这时有两种情况:
(1).公牛B配对成功另一头母牛,这时公牛A就可以配对原来的母牛。
(2).公牛B没有找到另一头母牛配对。这时标记一开始的这头母牛为“不可询问状态”,以后的其他公牛都不能询问这头母牛。 然后公牛A就要继续找其他母牛了。

那么,已经配对成功过母牛的公牛会不会丧偶?

从上面的第二种情况就可以看出,我们会确保公牛B有配偶,而不会没有配偶(是换配偶)

poj 1274 The Perfect Stall

题目中的母牛就是我们刚刚讲的公牛。产奶的地方就是母牛QAQ

提供非常标准的代码

#include<cstdio>
#include<cstring>
using namespace std;
int match[501];  //标记母牛的数组,match[i]为第i只母牛的匹配对象是第几只公牛
int n,m,ans; //n公牛数目,m母牛数目,ans为匹配对数
bool mp[401][501] ; //mp[i][j]==true表示第i只公牛和第j只母牛有匹配关系
bool chw[501];  // 也是标记母牛可否被“询问”的数组(“询问”后面有解释)。
   //如果第i只母牛chw[i]==false,表示母牛i不可被询问,否则表示母牛i可被“询问”。
   //匈牙利算法的关键点:chw数组
bool find_muniu(int x)
{
   for(int j=1;j<=m;j++)  //逐只母牛问
      if (mp[x][j]==true)  //第k只公牛和第i只母牛有匹配关系
         if (chw[j]==true)//问母牛i能否被“询问”
         {
            chw[j]=false; //标记母牛i已被询问,不管匹配成功与否,以后其他公牛都没必要再询问母牛i
            if ( match[j]==0 || find_muniu(match[j])==true )
            // match[i]=0 该母牛单身  或者 find(match[i])如果该母牛已匹配公牛x(x==match[i]),尝试让公牛x去找其他母牛匹配
            {
                match[j]=x;
                return true; //这两句表示第i只母年匹配了第k只公牛}
            }
         }
   return false;//执行到这一步表示匹配不成功。
}
int main()
{
   scanf("%d%d",&n,&m);//n只公牛,m只母年
   memset(mp,false,sizeof(mp));//初始化匹配关系
   for(int i=1;i<=n;i++)//读入边,构建图
   {
       int kk,y;scanf("%d",&kk); //混蛋,第i只公牛竟然能和kk只母牛匹配,她们是谁?
       for(int j=1;j<=kk;j++)
       {
           scanf("%d",&y);
           mp[i][y]=true;
       }
   }
   ans=0;//匹配对数初始化为0
   memset(match,0,sizeof(match));//每只母牛初始化为未匹配(match[i]=0)
   for(int i=1;i<=n;i++)  //公牛逐个逐个找母牛
   {
      memset(chw,true,sizeof(chw)); //所有母牛初始化为可“询问”
      if(find_muniu(i)==true)ans++;//如果找到了,总体增加一对
      //思考:匹配成功的公牛会不会被后来的公牛抢了母牛?
   }
   printf("%d\n",ans);//输出最大匹配对数
   for(int i=1;i<=m;i++)//询问每只母牛有没有匹配到公牛
      if(match[i]>0)   //如果母牛i已经匹配,输出匹配了哪只公牛
          printf("%d %d\n",match[i],i);
   return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值