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; }