bzoj2744 [HEOI2012]朋友圈——二分图匹配
Posted zinn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj2744 [HEOI2012]朋友圈——二分图匹配相关的知识,希望对你有一定的参考价值。
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2744
首先,求一个图的最大团等价于求它的补图的最大独立集,而二分图的最大独立集 = 总点数 - 最大匹配数;
所以先把图转化成补图,也就是A国奇、偶点各自成团,B国奇、偶点相互连边而其内部无边,还有些A到B的边用邻接矩阵存了;
可以发现A国最多只能选出两个点来,而A国选的那些点会影响B国的最大独立集;
发现A国点很少,不妨暴力枚举!
注意计算最大独立集时减去的数 tmp,原来写的是 tmp = 最大匹配数,其中左部点(B国奇数点)不管,右部点和A国点相连的也匹配;
想的是右部点中和A国相连的就算匹配上了也会算在减去的部分,但这样不太对呢,而且会少算左部点中和A国相连的;
所以直接再来一个 out 数组表示和A国点相连,把B国中左右部的 out 点都算上,然后匹配时不去匹配 out 的右部点;
虽然感觉挺麻烦但其实也挺好写的。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<vector> using namespace std; int const maxn=3005; int A,B,m,a[205],b[maxn],pre[maxn],ans,tmp,sid[205][maxn]; bool vis[maxn],out[maxn]; vector<int>vb[maxn]; bool dfs(int x) { for(int i=0;i<vb[x].size();i++) { int u=vb[x][i]; if(vis[u]||out[u])continue; vis[u]=1; if(!pre[u]||dfs(pre[u])){pre[u]=x;return 1;} } return 0; } bool ck(int x,int y) { int k=(x|y),ret=0; for(;k;k-=(k&-k))ret++; return (ret&1); } int main() { scanf("%d%d%d",&A,&B,&m); for(int i=1;i<=A;i++) { scanf("%d",&a[i]); // if(a[i]&1)a1.push_back(i); // else a2.push_back(i); } for(int i=1;i<=B;i++) { scanf("%d",&b[i]); for(int j=1;j<i;j++) { if(ck(b[i],b[j])||(b[i]^b[j])%2==0)continue;//补图上无边 vb[i].push_back(j),vb[j].push_back(i); } } for(int i=1,x,y;i<=m;i++){scanf("%d%d",&x,&y); sid[x][y]=1;} for(int j=1;j<=B;j++) { if(b[j]%2==0)continue;//不dfs右部点 memset(vis,0,sizeof vis); if(dfs(j))ans++; } ans=B-ans; for(int i=1;i<=A;i++) { tmp=0; memset(pre,0,sizeof pre); memset(out,0,sizeof out); for(int j=1;j<=B;j++)if(!sid[i][j])out[j]=1,tmp++;//补图上有边 for(int j=1;j<=B;j++) { if(b[j]%2==0||out[j])continue; // if(!sid[i][j]){tmp++; continue;} memset(vis,0,sizeof vis); if(dfs(j))tmp++; } tmp=B-tmp+1; ans=max(ans,tmp); } for(int i=1;i<=A;i++) { // int i=a1[ii]; if(a[i]%2==0)continue; for(int j=1;j<=A;j++) { if(a[j]%2==1)continue; // int j=a2[jj]; tmp=0; memset(pre,0,sizeof pre); memset(out,0,sizeof out); for(int k=1;k<=B;k++)if(!sid[i][j]||!sid[j][k])out[j]=1,tmp++;//! for(int k=1;k<=B;k++) { if(b[k]%2==0||out[k])continue;//补图上有边 memset(vis,0,sizeof vis); if(dfs(k))tmp++; } tmp=B-tmp+2; ans=max(ans,tmp); } } printf("%d ",ans); return 0; }
以上是关于bzoj2744 [HEOI2012]朋友圈——二分图匹配的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 2744 [HEOI2012]朋友圈——补图!+匈牙利算法