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 }
View Code

 

转载于:https://www.cnblogs.com/zstu-abc/p/3297708.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值