1. 程式人生 > >Kindergarten (二分匹配)

Kindergarten (二分匹配)

     In a kindergarten, there are a lot of kids. All girls of the kids know each other and all boys also know each other. In addition to that, some girls and boys know each other. Now the teachers want to pick some kids to play a game, which need that all players know each other. You are to help to find maximum number of kids the teacher can pick.
Input
    The input consists of multiple test cases. Each test case starts with a line containing three integers
    G, B (1 ≤ G, B ≤ 200) and M (0 ≤ M ≤ G × B), which is the number of girls, the number of boys and
    the number of pairs of girl and boy who know each other, respectively.
    Each of the following M lines contains two integers X and Y (1 ≤ X≤ G,1 ≤ Y ≤ B), which indicates that girl X and boy Y know each other.
    The girls are numbered from 1 to G and the boys are numbered from 1 to B.

    The last test case is followed by a line containing three zeros.
Output
    For each test case, print a line containing the test case number( beginning with 1) followed by a integer which is the maximum number of kids the teacher can pick.
Sample Input

    2 3 3
    1 1
    1 2
    2 3
    2 3 5
    1 1
    1 2
    2 1
    2 2
    2 3
    0 0 0

Sample Output

    Case 1: 3
    Case 2: 4

題意:有一群孩子,男孩之間互相認識,女孩之間互相認識,另外有部分男孩和女孩也是認識的。現在老師需要選出一個孩子集合,集合中所有的孩子都互相認識。求集合的最大元素個數。

分析:這道題是一個匹配題,那麼我們就要想辦法把各種情況轉化為最大匹配來算。

       首先我們可以通過題目的輸入構建一張圖,用鄰接矩陣表示,這張圖就是關係圖,如果兩個人認識,就記為1。不認識就記為0。然後我們可以把圖轉化為補圖,那麼補圖中有邊就表示這兩個人其實是不認識的,那麼我們要做的就是求最小頂點覆蓋(找最少的頂點覆蓋所有的邊),把這些頂點去除後補圖中就沒有邊了,那麼就表示在原圖中這些人是互相認識的。即求出答案。

【再來看這題,題目中,男生是一個點集,男生都互相認識,女生是一個點集,女生都互相認識,則這個圖的補圖肯定是二分圖。因為補圖的邊一個端點在男生點集,一個端點在女生點集。確認是二分圖後,求二分圖的最大獨立集】

#include<stdio.h>
#include<string.h>
int m,n,g,e[410][410],match[410],book[410];
int dfs(int u)
{
	int i;
	for(i = 1; i <= g; i ++)
	{
		if(book[i] == 0 && e[u][i] == 1)
		{
			book[i] = 1;
			if(match[i] == 0 || dfs(match[i]))
			{
				match[i] = u;
				return 1;
			}
		}
	}
	return 0;
}
int main()
{
	int i,j,k,x,y,sum,count=1;
	while(scanf("%d%d%d",&n,&m,&k), n!=0||m!=0||k!=0)
	{
		sum = 0;
		g = n + m;
		memset(e,0,sizeof(e));
		memset(match,0,sizeof(match));
		for(i = 1; i <= m; i ++)
			for(j = 1; j <= m; j ++)
				e[i][j] = 1;
		for(i = m+1; i <= g; i ++)
			for(j = m+1; j <= g; j ++)
				e[i][j] = 1;
		for(i = 0; i < k; i ++)
		{
			scanf("%d%d",&x,&y);
			e[x+m][y] = 1;
			e[y][x+m] = 1;
		}
		for(i = 1; i <= g; i ++)
			for(j = 1; j <= g; j ++)
				if(e[i][j] == 1)
					e[i][j] = 0;
				else
					e[i][j] = 1;
		for(i = 1; i <= g; i ++)
		{
			memset(book,0,sizeof(book));
			if(dfs(i))
				sum ++;
		}
		printf("Case %d: %d\n",count ++,g-(sum/2));
	}
	return 0;
}