洛谷P2423 [HEOI2012]朋友圈 (最大团+二分图匹配+补图) HQG_AC 的博客

【题目大意】

有两个国家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∈A∪B,对于所有的i,j∈S,i和j是朋友。 求最大的朋友圈的人数。
【声明】:

洛谷上的与BZOJ2744有一点区别,洛谷要先输入t,请做BZOJ的同学改一下代码。

【思路】:

Code:

#include 
using namespace std ;
const int MAX_B=3000 + 10 ;
bool mp[MAX_B][MAX_B] ;
vector <int> E[MAX_B] ;
int use1[MAX_B],use2[MAX_B],use3[MAX_B],result[MAX_B],a[MAX_B],b[MAX_B] ;
int m,cnt1,cnt2,na,nb,t,x,y ;
int calc(int x){
    int re=0 ;
    while (x) x-=x&-x,++re ;
    return re ;//有奇数个1 (奇数的二进制末尾一定=1) 
} 
bool dfs(int now){
    if (use1[now]==cnt1) return false;
    for (int i=0;iint to=E[now][i] ;
        if ((use1[to]!=cnt1) && (use2[to]!=cnt2)){
            use2[to]=cnt2;
            if (use3[to]!=cnt1 || !result[to] || dfs(result[to])){
                use3[to]=cnt1 ;
                result[to]=now ;
                return true ;
            }
        }
    }
    return false;
}
int xyl(int x=0,int y=0) 
{
    int t=0;cnt1++ ;
    for (int i=1;i<=nb;i++) if (mp[x][i] || mp[y][i]) use1[i]=cnt1,t++ ;
    //该点至少与A,B中的一个没有边,所以不可能成为独立集,排掉(A or B=0的情况已预处理过) 

    for (int i=1;i<=nb;i++){
        if (b[i]&1){
            ++cnt2 ;
            if (dfs(i)) t++ ;
        }
    }
    return (nb-t) ;

} 
void solve(){
    int ans=xyl() ;//选择0位A国人
    for (int i=1;i<=na;i++) 
    ans=max(ans,xyl(i)+1) ; //选择i号A国人 
    for (int i=1;i<=na;i++) if (a[i]&1) //选择i号A国人 
    for (int j=1;j<=na;j++) if (~a[j]&1) //选择j号A国人 
    ans=max(ans,xyl(i,j)+2) ;
    printf("%d\n",ans) ;
}
int main(){
    scanf("%d",&t) ;
    while (t--){
        memset(mp,1,sizeof(mp)) ;

        scanf("%d%d%d",&na,&nb,&m) ;//a国人的数量,b国人的数量,ab两国的朋友关系数 
        for (int i=1;i<=na;i++) scanf("%d",&a[i]) ;
        for (int i=1;i<=nb;i++) scanf("%d",&b[i]) ;
        for (int i=1;i<=m;i++){
            scanf("%d%d",&x,&y) ;
            mp[x][y]=0 ;
        }

        for (int i=1;i<=nb;i++) 
        if (b[i]&1)
        for (int j=1;j<=nb;j++)
        if (~b[j]&1)
        { //B[i] xor B[j] mod 2=0 
            if (~calc(b[i]|b[j])&1) E[i].push_back(j),E[j].push_back(i) ;
        }
        for (int i=1;i<=nb;i++) mp[0][i]=0;//预设,因为后面xyl时会有x,y等于0的情况 

        solve() ;
    }
    return 0 ;
}

你可能感兴趣的:(————图论————,二分图匹配,匈牙利,我的比赛总结)