poj 3692 & 2771 二部图最大独立集(选认识的孩子玩游戏)

3692题意:所有男孩都互相认识,所有女孩也互相认识。又已知有若干男生和女生互相认识。现在要选出最大的孩子集合,使得他们之间全部互相认识。

2771题意:几乎同上。只是多了一步需要判断男女能否在一起玩。之后的做法同3692.

思路:思路比较明确,如果把所有孩子看成顶点,认识连边构成图,则题意为求图的最大团。由最大团=补图的最大独立集可知相当于求补图的最大独立集。显然补图是二部图。那么根据二部图中最大独立集+最大匹配=V可知相当于求V-最大匹配。

注意一点:求二部图最大独立集的时候,下述算法是错误的:对于每个联通块进行黑白染色,然后把max(黑点数,白点数)加进答案。因为这样相当于是选择二部图中点数多的那部加入最大独立集中,但是实际上最大独立集可能在两部中都有点,而不一定选择一部的所有点,而另一部一个不选。反例如乙炔的碳骨架(把中间的双键用一条边相连)所形成的图,其二部图染色只有一种染色法,每一部都是三个点。但是其最大独立集是4个叶子组成的点集。

3692代码:

#include <stdio.h>
#include <string.h>
#define N 205
int n,m,k;
int used[N],link[N],g[N][N],c=1;
int dfs(int i){
	int j;
	for(j = 1;j<=m;j++)
		if(!used[j] && g[i][j]){
			used[j] = 1;
			if(link[j] == -1 || dfs(link[j])){
				link[j] = i;
				return 1;
			}
		}
	return 0;
}
int hungary(){
	int i,res=0;
	for(i = 1;i<=n;i++){
		memset(used,0,sizeof(used));
		if(dfs(i))
			res++;
	}
	return res;
}
int main(){
	while(scanf("%d %d %d",&n,&m,&k) && (m+n+k)){
		int i,j,a,b;
		memset(g,0,sizeof(g));
		memset(link,-1,sizeof(link));
		for(i = 0;i<k;i++){
			scanf("%d %d",&a,&b);
			g[a][b] = 1;
		}
		for(i = 1;i<=n;i++)
			for(j = 1;j<=m;j++)
				g[i][j] ^= 1;
		printf("Case %d: %d\n",c++,n+m-hungary());
	}
	return 0;
}
2771代码:
#include <stdio.h>
#include <string.h>
#include <math.h>
#define N 505
int T,n,m,sum;
struct node{
	int h;
	char s[100],t[100];
}boy[N],girl[N];
int g[N][N],used[N],link[N];
int dfs(int i){
	int j;
	for(j = 1;j<=m;j++)
		if(!used[j] && g[i][j]){
			used[j] = 1;
			if(link[j] == -1 || dfs(link[j])){
				link[j] = i;
				return 1;
			}
		}
	return 0;
}
int hungary(){
	int i,res=0;
	for(i = 1;i<=n;i++){
		memset(used,0,sizeof(used));
		if(dfs(i))
			res++;
	}
	return res;
}
int test(int a,int b){
	if(abs(boy[a].h-girl[b].h)>40)
		return 1;
	if(strcmp(boy[a].s,girl[b].s))
		return 1;
	if(!strcmp(boy[a].t,girl[b].t))
		return 1;
	return 0;
}
int main(){
	scanf("%d",&T);
	while(T--){
		int i,j;
		char ch;
		n = m = 0;
		memset(link,-1,sizeof(link));
		memset(g,0,sizeof(g));
		scanf("%d",&sum);
		for(i = 0;i<sum;i++){
			scanf("%d %c",&j,&ch);
			if(ch == 'M'){
				boy[++n].h = j;
				scanf("%s %s",boy[n].s,boy[n].t);
			}else{
				girl[++m].h = j;
				scanf("%s %s",girl[m].s,girl[m].t);
			}
		}
		for(i = 1;i<=n;i++)
			for(j = 1;j<=m;j++)
				if(test(i,j))
					g[i][j] = 1;
		for(i = 1;i<=n;i++)
			for(j = 1;j<=m;j++)
				g[i][j] ^= 1;
		printf("%d\n",n+m-hungary());
	}
	return 0;
}


你可能感兴趣的:(poj 3692 & 2771 二部图最大独立集(选认识的孩子玩游戏))