无权二分匹配——匈牙利算法

来源:互联网 发布:轩辕剑披风进阶数据 编辑:程序博客网 时间:2024/05/21 07:03

首先先明确几个概念:
二分匹配就是两个点的集合,想象成两根筷子一样,左边一列,右边一列,形如这种形式就是二分图;
另外,什么是匹配呢?简单来说,就是从左边找一个点,再从右边找一个点,与这两个点相连的点只有彼此(1对1);
最大匹配问题就是最多能找出来多少对这样的边;
另外,据我的理解(不一定对),网上说的利用交错边寻找增广路等等之所以那样要求也是为了保证同一个点只连接另外一个集合中的一个点——因为是交错的,那么其中一半的边是完全可以消去不看的,消去这部分边,剩下的就是一一对应的。
如果还是不懂,不要紧,接下来看一下大神如何通俗地讲明白这个问题:
趣写算法系列之匈牙利算法
看完通俗的,我还找到了一份专业的,供大家参考:
专业版
有了基本概念之后,来看一个模板题:

Courses
Problem Description
Consider a group of N students and P courses. Each student visits zero, one or more than one courses. Your task is to determine whether it is possible to form a committee of exactly P students that satisfies simultaneously the conditions:

. every student in the committee represents a different course (a student can represent a course if he/she visits that course)

. each course has a representative in the committee

Your program should read sets of data from a text file. The first line of the input file contains the number of the data sets. Each data set is presented in the following format:

P N
Count1 Student1 1 Student1 2 … Student1 Count1
Count2 Student2 1 Student2 2 … Student2 Count2
……
CountP StudentP 1 StudentP 2 … StudentP CountP

The first line in each data set contains two positive integers separated by one blank: P (1 <= P <= 100) - the number of courses and N (1 <= N <= 300) - the number of students. The next P lines describe in sequence of the courses . from course 1 to course P, each line describing a course. The description of course i is a line that starts with an integer Count i (0 <= Count i <= N) representing the number of students visiting course i. Next, after a blank, you’ll find the Count i students, visiting the course, each two consecutive separated by one blank. Students are numbered with the positive integers from 1 to N.

There are no blank lines between consecutive sets of data. Input data are correct.

The result of the program is on the standard output. For each input data set the program prints on a single line “YES” if it is possible to form a committee and “NO” otherwise. There should not be any leading blanks at the start of the line.

An example of program input and output:

Sample Input
2
3 3
3 1 2 3
2 1 2
1 1
3 3
2 1 3
2 1 3
1 1

Sample Output
YES
NO

简单来说,这个题就是问学生和课程能否一一匹配,一道十分简单的模板题,下面贴上我的代码。
虽然网上代码很多,可是许多看起来代码都是一样的(我的和那些看起来相似度也很高,但是确实是自己写的),建议小白还是最好自己打一遍,这样在修改的过程中可以加深自己的理解。

#include <iostream>#include <cstring>using namespace std;//最大数量#define maxsize 400//t样例数,p,n与题目同义int t,p,n;//如果相连为truebool map[maxsize][maxsize];//学生代表的课程名int match[maxsize];//该学生是否代表某一课程bool used[maxsize];//函数作用就是为第x门课找到匹配学生并且保证前面的课也有匹配,无法满足时返回falsebool dfs(int x){    int i,j,k;    //从学生中找    for(i=1;i<=n;i++)    {        //两点相连且当前一轮该学生没有被访问过        if(map[x][i]&&used[i]==false)        {            //学生现在被访问            used[i]=true;            //如果该学生没有代表任何课程或者可以通过修改之前的匹配关系把该学生“腾”出来,            //那么都可以让该学生代表x课            if(match[i]==-1||dfs(match[i])){            match[i]=x;            return true;//结束寻找,因为已经找到了            }        }    }    //没有    return false;}int hungry(){    int i,j,k;    int res=0;    memset(match,-1,sizeof(match));    //为每一个课挨个找匹配    for(i=1;i<=p;i++)    {        //每次寻找前,学生都是没有代表课程的        memset(used,false,sizeof(used));        //如果该课程找到代表学生,那么匹配数加一,在找的过程中会修改之前的匹配关系,        //只有当前课程即之前找的课程都匹配,当前课程才算找到匹配        if(dfs(i)) res++;    }    return res;}int main(){    cin>>t;    while(t--)    {        memset(map,false,sizeof(map));        cin>>p>>n;        int i,j;        for(i=1;i<=p;i++)        {            cin>>j;            while(j--)            {                int l;                cin>>l;                map[i][l]=true;            }        }        //如果可以一一对应        if(hungry()==p)        cout<<"YES"<<endl;        else        cout<<"NO"<<endl;    }    return 0;}

这一篇介绍没有权值的二分匹配,如果两点之间的连线是有权值的,那么就要用到KM算法,我会在下面一篇博客中介绍。

原创粉丝点击