Description
S∈A∪ B ,对于所有的i,j∈ S ,i 和 j 是朋友
由于落后的古代,没有电脑这个也就成了每年最大的难题,而你能帮他们求出最大朋 友圈的人数吗?
Input
Output
最开始的最开始,最大团=顶点数-补图的最大匹配数,(最大团当然是一个点的集合使得两两都有边)。
不知道会不会很多人一上来都会和我一样觉得这是一道裸的二分图最大匹配题,仔细想想好像并不是这样,主要是无法构建二分图的问题(集合内部也有边)。
接着仔细观察题目,发现对于A国,最多只会有两个公民被选中,因为一个必须为0,另一个则必须为1,如果再有0或1必然与一个不能构成朋友,那么我们知道了,A国选的人只能为0,1或2人。
再者发现b国的补图是a^b&1==1 且 a|b的位数为偶数,第一个条件确定了一个第一位必须是0,另一个必须是1,第二个条件规定了两个集合之间的边,那么很容易的看出了是二分图了,求可以直接求最大匹配,下面说一下如何求解的问题。
对于A国0人的情况,就是B国里的最大团了,直接求即可。
对于A国1人的情况,首先我们把能与该人构成好友的人选出来,因为答案就只会是这些人了,再对这些人做单独的最大团,答案就是max(0人情况,1人情况+1),在构建代码方面,我们可以使用一个flag来标记哪些人被选中,如果二分图匹配中遇到了一个没有选中的点,那么答案直接减去1即可。
对于A国2人的情况,与1人情况同理可得。
下附AC代码。
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#define maxn 3005
using namespace std;
int t1,t2;
int ans,n,m,q;
int rel[maxn][maxn];
vector<int>edge[maxn];
int a[maxn],b[maxn],vis[maxn],flag[maxn],match[maxn],tim[maxn];
int lowbit(int now)
{
return (now&(-now));
}
int count(int now)
{
int temp=0;
while(now){temp++;now-=lowbit(now);}
return temp;
}
int dfs(int now)
{
int len=edge[now].size();
for(int i=0;i<len;i++)
{
int nex=edge[now][i];
if(vis[nex]!=t2 && flag[nex]==t1)
{
vis[nex]=t2;
if(tim[nex]!=t2 || !match[nex] || dfs(match[nex]))
{
match[nex]=now;
tim[nex]=t2;
return true;
}
}
}
return false;
}
int solve()
{
int now=0;
for(int i=1;i<=m;i++)
{
if(flag[i]==t1)
{
t2++;
if(dfs(i))
now++;
}
else
now++;
}
return m-now;
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=m;i++)
scanf("%d",&b[i]);
for(int i=1;i<=q;i++)
{
int x,y;
scanf("%d%d",&x,&y);
rel[x][y]=1;
}
for(int i=1;i<=m;i++)
if(b[i]&1)
{
for(int j=1;j<=m;j++)
if(!(b[j]&1) && !(count(b[i]|b[j])&1))
{
edge[i].push_back(j);
}
}
ans=max(ans,solve());
for(int i=1;i<=n;i++)
{
t1++;
for(int j=1;j<=m;j++)
if(rel[i][j])
flag[j]=t1;
ans=max(ans,solve()+1);
}
for(int i=1;i<=n;i++)
if((a[i]&1))
{
for(int k=1;k<=n;k++)
if(!(a[k]&1))
{
t1++;
for(int j=1;j<=m;j++)
if(rel[i][j] && rel[k][j])
flag[j]=t1;
ans=max(ans,solve()+2);
}
}
printf("%d\n",ans);
}