首页 > 其他 > 详细

BZOJ 2744 [HEOI2012]朋友圈 二分图 最大团

时间:2018-09-09 20:23:11      阅读:181      评论:0      收藏:0      [点我收藏+]

$ \rightarrow $ 戳我进BZOJ原题 $ \rightarrow $ 戳我进洛谷原题

[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 \times 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(){
    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;
}

BZOJ 2744 [HEOI2012]朋友圈 二分图 最大团

原文:https://www.cnblogs.com/PotremZ/p/9614826.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!