【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 4Sample 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国的小朋友的影响就直接枚举就好了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
数据弱??一个很明显的错一开始还是AC了。。
2017-02-21 17:20:50