zoukankan      html  css  js  c++  java
  • BZOJ 2744 [HEOI2012]朋友圈 二分图 最大团

    $ ightarrow $ 戳我进BZOJ原题 $ ightarrow $ 戳我进洛谷原题

    [HEOI2012]朋友圈

    时空限制 $ quad $ 1000ms / 128MB

    题目描述

    在很久很久以前,曾经有两个国家和睦相处,无忧无虑的生活着。
     
    一年一度的评比大会开始了,作为和平的两国,一个朋友圈数量最多的永远都是最值得他人的尊敬,
    所以现在就是需要你求朋友圈的最大数目。两个国家看成是 $ A, B $ 两国,现在是两个国家的描述:
     
    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 in A cup B $ ,对于所有的 $ i,j in S , i $ 和 $ j $ 是朋友
     
    由于落后的古代,没有电脑这个也就成了每年最大的难题,而你能帮他们求出最大朋友圈的人数吗?
     

    输入输出格式

    输入格式

    第一行 $ t le 6 $ ,表示输入数据总数。

    对于每组数据:

    第一行三个整数 $ A,B,M $ ,分别表示 $ A $ 国人数, $ B $ 国人数, $ A, B $ 两国之间是朋友的对数
    第二行 $ A $ 个数 $ a_i $ ,表示 $ A $ 国第 $ i $ 个人的友善值
    第三行 $ B $ 个数 $ b_i $ ,表示 $ B $ 国第 $ i $ 个人的友善值
    第 $ 4~3+M $ 行,每行两个整数 $ x,y $ 表示 $ A $ 国的第 $ x $ 个人和 $ B $ 国第 $ y $ 个人是朋友
     

    输出格式

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

     

    输入输出样例

    输入样例

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

    输出样例

     5 
    

     

    说明

    最大朋友圈包含 $ A $ 国第 $ 1、2 $ 人和 $ B $ 国第 $ 1、2、3 $ 人

    第一类:$ |A| le 200, |B| le 200 $

    第二类:$ |A| le 10, |B| le 3000 $

    $ A le 200,B le 3000 $ ,友善为 $ int $ 类型正整数

    $ M le A imes B le 40000 $

    实际数据中 $ t=1 $

     

    题解

    • 观察原图:

    • $ A $ 国中的友善度奇偶性不同的点之间有边

    • $ B $ 国中所有奇数之间有边,所有偶数之间有边,奇偶不同的数之间一部分有边
       

    • 观察朋友圈定义:

    • 朋友圈是一个团

    • 一般图的最大团问题是 $ NPC $ 的,然而这个图的补图很特殊
       

    • 观察补图:

    • $ A $ 国的奇数值的点构成完全图,偶数值点构成完全图

    • $ B $ 国的奇数点和偶数点构成二分图

    • 补图上朋友圈的定义:

    • 朋友圈是一个独立集(最大团=补图最大独立集)

    • $ A $ 国最多取两个点,可以枚举两个点 $ x,y $ ,然后删除与 $ x,y $ 之间有边的 $ B $ 国的点

    • 在 $ B $ 国剩余的点上求二分图最大独立集
       

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    #define N 3010
    vector<int>e[N];
    int A,B,m,T1,T2,ans,a[205],b[N],mp[205][N],tag[N],vis[N],tim[N],lik[N];
    bool dfs(int u){
    	for(int i=0;i<e[u].size();++i){
    		int v=e[u][i];
    		if(tag[v]==T1&&vis[v]!=T2){
    			vis[v]=T2;
    			if(tim[v]!=T2||!lik[v]||dfs(v)){
    				lik[v]=u;
    				tim[v]=T2;
    				return 1;
    			}
    		}
    	}
    	return 0;
    }
    int Count(int x){
    	int res=0;
    	for(int i=x;i;i-=(i&-i)) ++res;
    	return res;
    }
    int solve(){
    	int res=0;
    	for(int i=1;i<=B;++i)
    		if(tag[i]==T1){
    			++T2;
    			if(dfs(i)) ++res;
    		} else ++res;
    	return B-res;
    }
    int main(){
    	//int t; scanf("%d",&t); //洛谷上需要读入t哦
    	scanf("%d %d %d",&A,&B,&m);
    	for(int i=1;i<=A;++i) scanf("%d",&a[i]);
    	for(int i=1;i<=B;++i) scanf("%d",&b[i]);
    	for(int i=1;i<=m;++i){
    		int u,v;
    		scanf("%d %d",&u,&v);
    		mp[u][v]=1;
    	}
    	for(int i=1;i<=B;++i)
    		if(b[i]&1)
    			for(int j=1;j<=B;++j)
    				if(!(b[j]&1))
    					if(!(Count(b[i]|b[j])&1)) 
    						e[i].push_back(j);
    	ans=max(ans,solve());
    	for(int i=1;i<=A;++i){
    		++T1;
    		for(int j=1;j<=B;++j)
    			if(mp[i][j]) tag[j]=T1;
    		ans=max(ans,solve()+1);
    	}
    	for(int i=1;i<=A;++i)
    		if(a[i]&1)
    			for(int j=i+1;j<=A;++j)
    				if(!(a[j]&1)){
    					++T1;
    					for(int k=1;k<=B;++k)
    						if(mp[i][k]&&mp[j][k]) tag[k]=T1;
    					ans=max(ans,solve()+2);
    				}
    	printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    在VS2010下,用C语言编写pthread多线程程序的配置
    java帮助文档系列JDK1.5 JDK1.6 JDK1.7官方中英完整版下载
    瑜伽练习day02----适合练习瑜伽时听的歌曲
    瑜伽练习day01----瑜伽练习的好处,坏处
    抛出错误Debug Assertion Failed!
    stringstream的基本用法
    AWS中S3的Bucket桶访问策略
    AWS中SQS的几项使用注意
    AWS在.Net中连接数据库时发生认证错误的解决办法
    .Net捕捉配置或程序错误
  • 原文地址:https://www.cnblogs.com/PotremZ/p/BZOJ2744.html
Copyright © 2011-2022 走看看