您的位置:首页 > 其它

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

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

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

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

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

3692代码:

#include <stdio.h>
#include <string.h>
#define N 205
int n,m,k;
int used
,link
,g

,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
,girl
;
int g

,used
,link
;
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
.s,boy
.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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: