【二分匹配】入门理解----Girls and Boys

二分匹配模板理解

基本思想:没有机会,就创造机会嘛

二分图:

二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。

简单的说,一个图被分成了两部分,相同的部分没有边,那这个图就是二分图,二分图是特殊的图。

匈牙利算法的思想:对于一个点,每次找到可以匹配的点,就去连接。下一个点如果没有点可以匹配了,那么直接把上一个已经匹配的点做修改,再来寻找能否匹配。

//匈牙利算法
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 1005
int n,m,ans;
//n公牛数目,m母牛数目,ans为匹配对数
int k,h;
bool ac[maxn][maxn];
//ac[i][j]==true表示第i只公牛和第j只母牛有匹配关系
bool cw[maxn];
// 标记母牛可否被“询问”的数组(“询问”后面有解释)
int yy[maxn];
//标记母牛的数组,yy[i]为第i只母牛的匹配对象是第几只公牛
bool find(int x){
    for(int i=1;i<=m;i++){//逐个询问母牛
        if(ac[x][i]==true){//这只公牛和第i母牛有匹配关系
            if(cw[i]==true){//母牛可被询问
            
                cw[i]=false;//标记这只母牛不可询问了
                if(yy[i]==0 || find(yy[i])==true){
//yy[i]=0 该母牛单身  或者
// find(yy[i])如果该母牛已匹配公牛x(x==yy[i]),尝试让公牛x去找其他母牛匹配
                    yy[i]=x;
                    return true;
             //这两句表示第i只母年匹配了第x只公牛
                }
            }
        }
    }
     return false;
     //执行到这一步表示匹配不成功。
}

int main(){
    scanf("%d%d",&n,&m);
    memset(ac,false,sizeof(ac));//初始化匹配关系,都未匹配
    for(int i=1;i<=n;i++){//读入边,构建图
        scanf("%d",&k);//第i只公牛和 k只母牛匹配
        for(int j=1;j<=k;j++){
            scanf("%d",&h);//k只母牛的编号
            //第i公牛和第h母牛呈匹配关系
            ac[i][h]=true;
        }
    }
    ans=0;
    //每只母牛初始化为未匹配(match[i]=0)
    memset(yy,0,sizeof(yy));
    //遍历公牛去匹配
    for(int i=1;i<=n;i++){
        //所有母牛初始化为可“询问”
        memset(cw,true,sizeof(cw));
        if(find(i)==true){
            ans++;
        }
    
        }
        printf("%d\n",ans);
        printf("母牛的匹配情况(母牛---公牛):\n");
        for(int i=1;i<=m;i++){
        printf("%d----%d\n",yy[i],i);
        return 0;
    }
}

参考大神https://blog.csdn.net/qq_36038511/article/details/69526128

趣味理解:https://blog.csdn.net/dark_scope/article/details/8880547

 

 

 

 

Girls and Boys

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3019    Accepted Submission(s): 1294


 

Problem Description

the second year of the university somebody started a study on the romantic relations between the students. The relation “romantically involved” is defined between one girl and one boy. For the study reasons it is necessary to find out the maximum set satisfying the condition: there are no two students in the set who have been “romantically involved”. The result of the program is the number of students in such a set.

The input contains several data sets in text format. Each data set represents one set of subjects of the study, with the following description:

the number of students
the description of each student, in the following format
student_identifier:(number_of_romantic_relations) student_identifier1 student_identifier2 student_identifier3 ...
or
student_identifier:(0)

The student_identifier is an integer number between 0 and n-1, for n subjects.
For each given data set, the program should write to standard output a line containing the result.

 

 

Sample Input

7 0: (3) 4 5 6 1: (2) 4 6 2: (0) 3: (0) 4: (2) 0 1 5: (1) 0 6: (2) 0 1 3 0: (2) 1 2 1: (1) 0 2: (1) 0

 

 

Sample Output

5 2

 

思路:

二分图匹配 (hungary算法 )
找出一个最大的集合使得该集合的任意两个人没有关系。根据最大独立集 =顶点数 - 最大匹配数
//题目未知男生女生数量,也就是说没有明显的二分图.假定男女各为n,
//所以最大匹配数应该是求出来的数除以2 ,
//最后再用顶点数减就行了

 

原创代码

 

使用二分匹配模板

#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 1005
int n,num,a,b;
bool ac[maxn][maxn];//ac[i][j]表示男生i和女生j匹配
bool cw[maxn];//记录女生可否被询问
int yy[maxn];//记录女生,yy[i]=j表示女生i的搭档是男生j
int ans;//配对数
bool find(int x){
    for(int i=0;i<n;i++){
    if(ac[x][i]==true){//女生i可搭档男生x
        if(cw[i]==true){//女生i可被询问
            cw[i]=false;//标记这位女生
            if(yy[i]==0 || find(yy[i])==true){
            //这位女生单身或者让这位女生的搭档去找另外的女生并且找得到
                yy[i]=x;
                return true;
            }
        }
    }
}
return false;
}
int main(){
    while(scanf("%d",&n)!=EOF)
    {
        memset(ac,false,sizeof(ac));//初始化
        for(int i=0;i<n;i++){
            scanf("%d: (%d)",&a,&num);
            for(int j=0;j<num;j++){
            scanf("%d",&b);
            ac[a][b]=true;//表示a--b可配对
        }        
    }
    ans=0;
    memset(yy,0,sizeof(yy));
    for(int i=0;i<n;i++){//逐个男生去找搭档
        memset(cw,true,sizeof(cw));
        if(find(i)==true){
            ans++;
        }
    }
    int end=n-ans/2;
    printf("%d\n",end);
}
return 0;
}

 

使用邻接表+dfs+二分匹配

//hungary算法
#include<stdio.h>
#include<string.h>
const int MAXN=1000;

int map[MAXN][MAXN];//map[i][j]表示男生i和女生j匹配
int linker[MAXN];//记录女生,linker[i]=j表示女生i的搭档是男生j (-1表示单身)
bool used[MAXN];//记录女生可否被询问 (false表示可被询问)
int n;
//深搜
bool dfs(int a)
{
    for(int i=0;i<n;i++)
      if(map[a][i]&&!used[i])//男生a和女生i可匹配 && 女生可被询问
      {
          used[i]=true;//标记不可询问
          if(linker[i]==-1||dfs(linker[i]))//女生单身或者让她搭档找别人且找得到
          {
              linker[i]=a;
              return true;
          }    
      }
      return false;    
}

int hungary()
{
    int result=0;
    memset(linker,-1,sizeof(linker));//初始女生全单身
    for(int i=0;i<n;i++)//逐个男生去找搭档
    {
        memset(used,false,sizeof(used));
        if(dfs(i))  result++;
    }
    return result;   
}
int main()
{

    int i,j,num,a,b;
    while(scanf("%d",&n)!=EOF)
    {
        memset(map,0,sizeof(map));
        for(i=1;i<=n;i++)
        {
                scanf("%d: (%d)",&a,&num);
                for(j=0;j<num;j++)
                {
                    scanf("%d",&b);
                    map[a][b]=1;//1表示a--b可匹配
                }    
        }
        int cnt=hungary();
        printf("%d\n",n-cnt/2);
        
    }  
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值