HDU1068(二分图基础题 匈牙利算法 Girls and Boys )

题目等材料来源于网络
In 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.

INPUT

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 (n <=500 ), for n subjects.

OUTPUT

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

题意

给定数字n,有n个人从0开始编号到n-1,接下去n行,第i行第一个数字为第i个人的编号,(m)表示有m个人与这个人配对,接下去输入这每个人的编号;

解析

二分图法,对每个人的编号看作是一个顶点,i的配对对象有mj,看成是i到mj的有向边,则有出度的顶点就是有匹配的,只有出度的就是没有匹配。可以先求有匹配的对数,但由于是不考虑性别的求,所以结果要除以2,n - 有出度的顶点个数/2 即为所求。


#include
#include
#include 
#include
#include
#include 
#include
using namespace std;
#define rep(i, a, b) for(int i=(a); i<(b); i++)
#define req(i, a, b) for(int i=(a); i<=(b); i++)
#define ull unsigned __int64
#define sc(t) scanf("%d",&(t))
#define sc2(t,x) scanf("%d%d",&(t),&(x))
#define pr(t) printf("%d\n",(t))
#define pf printf
#define prk printf("\n")
#define pi acos(-1.0)
#define ms(a,b) memset((a),(b),sizeof((a)))
#define mc(a,b) memcpy((a),(b),sizeof((a))) 
#define w while
typedef long long ll;
typedef vector<int> vi;
//还是二分图的题,而且比较简单,把每个编号的人看成顶点,看成是有向图间的联通
//因为寻找时不分性别,所以结果任需除以2; 
//有些有些同学可能刚学二分图(匈牙利算法),我就注释的清楚一些 

vi s[505]; //s[i]中的i标记左半部分,是s[i][j],j是i的匹配对象,相当于给i和j连上一条i走向j的有向连线 
bool f[505];//标记是否遍历过 
int match[505];//标记是否已经处理过,以及记录匹配的点,下面注释说明 
int n, id, m, k, cnt;//人数、编号、匹配人数、匹配编号、匹配成功的对数 
char c;//输入缓冲 

bool find(int x) //关键代码 
{
    int u, v;
    rep(i, 0, s[x].size())
    {
        u = s[x][i]; //对于每一个x(即每一个编号的人),查探与他连线的人 
        v = match[u];
        if(!f[u]) //为0说明没有遍历过 
        {
            f[u] = 1;//标记走过 
            if(v < 0 || find(v)) //match[u]<0 说明与x连线的这个点还没有走过,可用
                                 //如果v>=0,说明走过了,但是像(1,2)(1,4)(3,2)
                                  //搜索1的时候,2号先被使用,match[2]=1,2号被标记,但是搜索3的时候,3可以与2匹配,
                                  //这时match[2]=1>0,但是第二个条件v=match[2]=1,find(1)因为还可以使用4号,所以2号重新可被3号匹配
                                  //如果此时1无法找到新的匹配,就不会腾出2号的匹配位置,3号就无法匹配 
            {
                match[u] = x; //这里记录为x就是上面说的用处 
                return true;
            }
        }
    }
    return false;
}

int main()
{
    w(~sc(n) && n)//文本输入 
    {
        cnt = 0;
        rep(i, 0, 505)//重置 
        s[i].clear();
        ms(match, -1);//初始化 
        req(i, 1, n)
        {              //输入 
            getchar();
            scanf("%d%c", &id, &c);
            getchar();
            scanf("%c%d%c)", &c,&m,&c);
            if(m == 0)
            continue;
            req(j, 1, m)
            {
                sc(k);
                s[id].push_back(k);
            }
        }
        rep(i, 0, n) //编号是[ 0, n),遍历每一个人,寻找是否与人匹配 
        {
            ms(f, false);
            if(find(i)) //如果匹配,匹配对数+1 
            cnt++;
        }
        pr(n - cnt/2); //因为这里的匹配没有分男女,所以结果要除以2 
     } 
}

你可能感兴趣的:(HDU1068(二分图基础题 匈牙利算法 Girls and Boys ))