UVALive 3415 Guardian of Decency(二分图的最大独立集)
题意:老师在选择一些学生做活动时,为避免学生发生暧昧关系,就提出了四个要求。在他眼中,只要任意两个人符合这四个要求之一,就不可能发生暧昧。现在给出n个学生关于这四个要求的信息,求老师可以挑选出的最大学生数量。
分析:
1、这里的问题可以抽象成求最大独立集:若两人发生暧昧,则在两人中建边,当四个条件中任意一个成立,则将两个人孤立。老师选择的学生必然是两两之间不会发生暧昧的。
公式:最大独立集=顶点总数V-最小点覆盖
2、这里涉及到离散数学中一些集合的概念,理解起来对在下实属不易,所以就先记住吧。(定义也只是挑重要的记录下来)
独立集:该集合中的点,两两之间不相邻(没有边)(单独一个点就是独立集)。一个图中含顶点数目最多的独立集称为最大独立集。
支配集:满足图上任意一个点要么就在集合内,要么也是与集合中的点相邻(顶点集V即是支配集)。一个图中含顶点数最少的支配集称为最小支配集。
最小点覆盖:当一个点被选入集合,认为与之相连的边都被覆盖了。在能够覆盖所有边的前提下,顶点数最少的集合称为最小点覆盖。
团:与独立集相反,集合中的点两两之间都相邻。一个图中含顶点数最多的团称为最大团。
性质:
最大独立集+最小覆盖集=V
最大团=补图的最大独立集
最小覆盖集=最大匹配
3、这里提到了一个最大独立集的样例:http://my.opera.com/IloveLunamaria/blog/show.dml/810972
其中最赞的一个观点:一般的用二分图匹配解决的问题,都是要证明题目条件等价于“匹配”,就是题目条件等价于“选择一些边,使得每个点都只在一条边中。
必须明确概念,才去做题目。最大独立集本身与最大匹配无关,是因为其在数学上与最小点覆盖集合互补,又有可以用最大匹配解决最小点覆盖,所以才得出:可以用最大匹配解最大独立集。
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<vector> 5 #include<algorithm> 6 #define clr(a,m) memset(a,m,sizeof(a)) 7 #define rep(i,a,b) for(int i=a;i<=b;i++) 8 using namespace std; 9 10 const int MAXN=555; 11 12 struct Person{ 13 int h; 14 char sex[2],music[111],sport[111]; 15 }p[MAXN]; 16 17 int n,ans,man,woman; 18 19 vector<int>G[MAXN]; 20 vector<int>row,col; 21 22 int left[MAXN],right[MAXN],S[MAXN],T[MAXN]; 23 24 void init() 25 { 26 rep(i,1,n) 27 G[i].clear(); 28 } 29 30 bool check(int i,int j) 31 { 32 if(fabs(p[i].h-p[j].h)>40)return false; 33 if(strcmp(p[i].sex,p[j].sex)==0)return false; 34 if(strcmp(p[i].music,p[j].music)!=0)return false; 35 if(strcmp(p[i].sport,p[j].sport)==0)return false; 36 return true; 37 } 38 39 void read() 40 { 41 init(); 42 rep(i,1,n) 43 scanf("%d%s%s%s",&p[i].h,p[i].sex,p[i].music,p[i].sport); 44 man=1; 45 rep(i,1,n) 46 if(p[i].sex[0]=='M'){ 47 woman=1; 48 rep(j,1,n){ 49 if(p[j].sex[0]=='F'){ 50 if(check(i,j)) 51 G[man].push_back(woman); 52 woman++; 53 } 54 } 55 man++; 56 } 57 } 58 59 bool match(int u) 60 { 61 S[u]=true; 62 int sz=G[u].size(); 63 rep(i,0,sz-1){ 64 int v=G[u][i]; 65 if(!T[v]){ 66 T[v]=true; 67 if(!left[v]||match(left[v])){ 68 left[v]=u; 69 right[u]=v; 70 return true; 71 } 72 } 73 } 74 return false; 75 } 76 77 void AP() 78 { 79 rep(i,1,woman)left[i]=0; 80 rep(i,1,man)right[i]=0; 81 82 ans=0; 83 rep(i,1,man){ 84 rep(j,1,man)S[j]=0; 85 rep(j,1,woman)T[j]=0; 86 if(match(i)) 87 ans++; 88 } 89 } 90 91 void print() 92 { 93 printf("%d\n",n-ans); 94 } 95 96 int main() 97 { 98 int T; 99 scanf("%d",&T); 100 while(T--) 101 { 102 scanf("%d",&n); 103 read(); 104 AP(); 105 print(); 106 } 107 return 0; 108 }