HDU2422 The Accomodation of Students

 http://acm.hdu.edu.cn/showproblem.php?pid=2444

有些人互相认识,但认识不具有传递性,比如A认识B,B认识C,不代表A认识C。给出所有认识关系,问能不能分成两个班,每个班里的人互相不认识。如果可以,一间宿舍可以住两个人,这两个人必须互相认识,问最多分配多少宿舍。

二分图判断和最大匹配。

分成不同的班相当于能不能构成二分图,分宿舍就是最大匹配。

注意能构成二分图不代表最大匹配是n/2。(n为点的个数)

关于二分图判断和最匹配的讲解在我的另一篇博客。

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#define INF 0x3f3f3f3f
#define me(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=210;
int n,m,line[N][N],ans[N],color[N];
bool used[N];
bool dfs(int u,int c)
{
	color[u]=c;
	for(int i=1;i<=n;i++)
	{
		if(!line[u][i])
			continue;
		if(!color[i])
		{
			if(dfs(i,-c))
				continue;
			return false;
		}
		else
			if(color[i]+color[u])//相同颜色说明不能构成二分图
				return false;//不同颜色就是一个-1,一个1,相加为0,为假,所以不会执行下面的return 
	}
	return true;
}
bool find(int x)
{
	for(int i=1;i<=n;i++)
		if(line[x][i]&&!used[i])
		{
			used[i]=1;
			if(!ans[i]||find(ans[i]))
			{
				ans[i]=x;
				return 1;
			}
		}
	return 0;	
} 
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		me(line,0);
		for(int i=0;i<m;i++)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			line[u][v]=1;//如果在这里建双向边,那么cnt即最大匹配会是两倍,匹配里的每一条边被算了两边 
		}
		me(color,0);
		bool f=1;
		for(int i=1;i<=n&&f;i++)
		{
			if(!color[i]&&!dfs(i,1))
				f=0;
		}
		if(!f)
			printf("No\n");
		else
		{
			me(ans,0);//别忘在这里初始化 
			int cnt=0;
			for(int i=1;i<=n;i++)
			{
				me(used,0);
				if(color[i]&&find(i))
					cnt++;
			}
			printf("%d\n",cnt);
		}
	}
} 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章