【BZOJ 2744】 2744: [HEOI2012]朋友圈 (最大团,二分图匹配,构图)

2744: [HEOI2012]朋友圈

Description

在很久很久以前,曾经有两个国家和睦相处,无忧无虑的生活着。一年一度的评比大会开始了,作为和平的两国,一个朋友圈数量最多的永远都是最值得他人的尊敬,所以现在就是需要你求朋友圈的最大数目。
两个国家看成是AB两国,现在是两个国家的描述:
1.         A国:每个人都有一个友善值,当两个A国人的友善值a、b,如果a xor b mod 2=1,
那么这两个人都是朋友,否则不是;
2.         B国:每个人都有一个友善值,当两个B国人的友善值a、b,如果a xor b mod 2=0
或者 (a or b)化成二进制有奇数个1,那么两个人是朋友,否则不是朋友;
3.         A、B两国之间的人也有可能是朋友,数据中将会给出A、B之间“朋友”的情况。
4.     在AB两国,朋友圈的定义:一个朋友圈集合S,满足

S∈A∪ B                  ,对于所有的i,j∈  S ,i 和       j   是朋友

由于落后的古代,没有电脑这个也就成了每年最大的难题,而你能帮他们求出最大朋 友圈的人数吗?

Input

第一行t<=6,表示输入数据总数。
接下来t个数据:
第一行输入三个整数A,B,M,表示A国人数、B国人数、AB两国之间是朋友的对数;第二行A个数ai,表示A国第i个人的友善值;第三行B个数bi,表示B国第j个人的友善值;
第4——3+M行,每行两个整数(i,j),表示第i个A国人和第j个B国人是朋友。

Output

输出t行,每行,输出一个整数,表示最大朋友圈的数目。

Sample Input

2 4 7
1 2
2 6 5 4
1 1
1 2
1 3
2 1
2 2
2 3
2 4

Sample Output

5
【样例说明】
最大朋友圈包含A国第1、2人和B国第1、2、3人。

HINT

【数据范围】

两类数据

第一类:|A|<=200 |B| <= 200

第二类:|A| <= 10 |B| <= 3000

 

 

【分析】

  %%%大颓果:http://blog.csdn.net/u010336344/article/details/56287207

  普通的最大团貌似是NPC问题??

  所以这题一定有特殊性质?

  A国不奇偶的认识,明显最多只能选2个人。

  B过同奇同偶的认识,如果认识的连边,那么有两个完全图,又有or什么的也是朋友,所以两个团中间还有边。

  那么其实可以建反图求最大点独立集。

  A国的小朋友的影响就直接枚举就好了。

 

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 using namespace std;
  7 #define Maxn 3010
  8 
  9 int mymax(int x,int y) {return x>y?x:y;}
 10 
 11 int a[Maxn],b[Maxn];
 12 
 13 struct node
 14 {
 15     int x,y,next;
 16 }t[Maxn*Maxn];
 17 int first[Maxn],len;
 18 
 19 void ins(int x,int y)
 20 {
 21     t[++len].x=x;t[len].y=y;
 22     t[len].next=first[x];first[x]=len;
 23 }
 24 
 25 int bx[Maxn],by[Maxn];
 26 bool vis[Maxn];
 27 bool eg[Maxn][Maxn];
 28 
 29 int chw[Maxn],match[Maxn];
 30 
 31 bool ffind(int x,int nt)
 32 {
 33     for(int i=first[x];i;i=t[i].next) if(chw[t[i].y]!=nt&&vis[t[i].y])
 34     {
 35         int y=t[i].y;
 36         chw[y]=nt;
 37         if(match[y]==0||ffind(match[y],nt))
 38         {
 39             match[y]=x;
 40             return 1;
 41         }
 42     }
 43     return 0;
 44 }
 45 
 46 int get_ans()
 47 {
 48     int ans=0,nt=0,h=0;
 49     for(int i=1;i<=bx[0]+by[0];i++) if(vis[i]) h++;
 50     memset(chw,0,sizeof(chw));
 51     memset(match,0,sizeof(match));
 52     for(int i=1;i<=bx[0];i++) if(vis[bx[i]])
 53     {
 54         nt++;
 55         if(ffind(bx[i],nt)) ans++;
 56     }
 57     return h-ans;
 58 }
 59 
 60 bool check(int x)
 61 {
 62     int nw=0;
 63     while(x)
 64     {
 65         if(x&1) nw++;
 66         x>>=1;
 67     }
 68     return nw&1;
 69 }
 70 
 71 int main()
 72 {
 73     int n,m,k;
 74     scanf("%d%d%d",&n,&m,&k);
 75     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
 76     for(int i=1;i<=m;i++) scanf("%d",&b[i]);
 77     bx[0]=by[0]=0;
 78     for(int i=1;i<=m;i++) if(b[i]&1) bx[++bx[0]]=i;
 79     for(int i=1;i<=m;i++) if(!(b[i]&1)) by[++by[0]]=i;
 80     for(int i=1;i<=bx[0];i++)
 81      for(int j=1;j<=by[0];j++)
 82      {
 83          if(!check(b[bx[i]]|b[by[j]]))  ins(bx[i],by[j]);
 84      }
 85     for(int i=1;i<=m;i++) vis[i]=1;
 86     int ans=get_ans();
 87     
 88     memset(eg,0,sizeof(eg));
 89     for(int i=1;i<=k;i++)
 90     {
 91         int x,y;
 92         scanf("%d%d",&x,&y);
 93         eg[x][y]=1;
 94     }
 95     
 96     for(int i=1;i<=n;i++)
 97     {
 98         for(int j=1;j<=m;j++) vis[j]=eg[i][j];
 99         ans=mymax(ans,get_ans()+1);
100         for(int j=1;j<=m;j++) vis[j]=1;
101     }
102     for(int i=1;i<=n;i++)
103     {
104         for(int ii=i+1;ii<=n;ii++) if((a[i]&1)^(a[ii]&1))
105         {
106             for(int j=1;j<=m;j++) vis[j]=eg[ii][j]&eg[i][j];
107             ans=mymax(ans,get_ans()+2);
108             for(int j=1;j<=m;j++) vis[j]=1;
109         }
110     }
111     printf("%d\n",ans);
112     return 0;
113 }
View Code

 

数据弱??一个很明显的错一开始还是AC了。。

 

2017-02-21 17:20:50

posted @ 2017-02-21 17:14  konjak魔芋  阅读(333)  评论(0编辑  收藏  举报