这题刚上来就看的这题,用模拟写啊写,又用贪心写啊写。。。我抽象成图了,然后删掉出度最多的(也就被最讨厌的人最多的),然后这么删,WA了,又改成删掉被喜欢最少的,还是WA。。。怎么YY都不行 T T 。。。
然后就去看其他题了。
瞟见群里说这题是二分匹配= =。。。二分匹配。。。怎么也想不出来。。
又去看别的题了。。。实在木题可做了。就回来看这个。
想了好多建图方法,郁闷死了。
后来想了,如果小朋友1喜欢D1而小朋友2讨厌D1,那么这俩建边,就这么弄,然后结果就是定点数 - 最大匹配数。
然后就这么建了,WA了。哭。本来想着不用建小朋友1讨厌KK和小朋友x喜欢KK这条边,因为之前应该都建过了,后来把建好的图输出,发现不对称 T T。。。确实是这点错了,改了后 A掉。
刚搜了下网上的,他们建图和我不一样,他们是把猫猫和狗狗建一块了。我又翻了翻黑书,最小路径覆盖最大独立集神马的总是弄不清楚。现在理解了。
这个是最大独立集哈,刚刚咨询了群里的同学,感谢他的解惑哈。
最大独立集:集合中任意俩元素没有关系(或者没有你给定的矛盾关系),最大独立集 = 顶点数 - 最大匹配。
所以就把一个人拆点,建立关系,那么求得的答案就是顶点数 - 最大匹配数/2。因为求得的关系必然是每个点包括了两次。
#include <queue> #include <stack> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <iostream> #include <limits.h> #include <string.h> #include <string> #include <algorithm> using namespace std; const int MAX = 750; int map[MAX][MAX]; int a[MAX][MAX]; int used[MAX],mat[MAX]; int Augment(int s,int n,int x) { int i; for(i=s; i<n; i++) if( !used[i] && a[x][i] ) { used[i] = 1; if( mat[i] == -1 || Augment(s,n,mat[i]) ) { mat[i] = x; return 1; } } return 0; } int Hungary(int s,int n) { int i,sum = 0; memset(mat,-1,sizeof(mat)); for(i=s; i<n; i++) { memset(used,0,sizeof(used)); if( Augment(s,n,i) ) sum++; } return sum; } int main() { int n,m,p,cnt; char s[150],ch; while( ~scanf("%d%d%d",&n,&m,&p) ) { memset(map,0,sizeof(map)); memset(a,0,sizeof(a)); for(int i=0; i<p; i++) { int k; scanf("%s",s); sscanf(s,"%c%d",&ch,&k); if( ch == 'C' ) map[i][p+k-1] = 1; else map[i][p+n+k-1] = 1; scanf("%s",s); sscanf(s,"%c%d",&ch,&k); if( ch == 'C' ) map[p+k-1][i] = 1; else map[p+n+k-1][i] = 1; } cnt = n + m + p; for(int i=0; i<p; i++) { for(int k=p; k<cnt; k++) if( map[i][k] ) for(int l=0; l<p; l++) if( map[k][l] ) a[i][l] = 1; for(int k=p; k<cnt; k++) if( map[k][i] ) for(int l=0; l<p; l++) if( map[l][k] ) a[i][l] = 1; } int ans = Hungary(0,p); printf("%d\n",p-ans/2); } return 0; }