简单的二分图dfs查找。
题意:给定n对关系u,v,表示u,v属于不同种族,问一个种族最大有多少人。
思路:给定一对关系后,就可以把两个点归类到不同集合A,B中,这样就形成了一个二分图,要求A中与B中最多有多少个点,首先dfs染色,染色完后继续dfs找A,B中分别有多少个点。需要特别注意的就是,要考虑图是否连通,所以就要用并查集来区分开互不连通的点集,对每个连通分量再进行上面所说的两次DFS。具体见代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define sf scanf
#define pf printf
using namespace std;
const int N=20005;
vector<int> G[N];
bool ex[N],vis[N],c[N];
int ans1,ans2,fa[N];
void unit()
{
memset(c,0,sizeof(c));
memset(vis,0,sizeof(vis));
memset(ex,0,sizeof(ex));
for(int i=1;i<N;i++)
fa[i]=i,G[i].clear();
}
void dfs(int u)//dfs染色
{
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(!vis[v])
{
vis[v]=1;
c[v]=!c[u];
dfs(v);
}
}
}
void dfs1(int u)//找单个连通分量中的点两种类型的点的个数
{
if(c[u]==0) ans1++;
else ans2++;
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(vis[v])
vis[v]=0,dfs1(v);
}
}
int root(int a)
{
if(a==fa[a]) return a;
else return fa[a]=root(fa[a]);
}
int main()
{
int i,x,y,n,m,T,ca=0;
sf("%d",&T);
while(T--)
{
sf("%d",&n);
unit();
int _max=-1;
while(n--)
{
sf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
ex[x]=ex[y]=1;
x=root(x),y=root(y);//并查集实现合并
fa[x]=y;
x=max(x,y);
_max=max(_max,x);
}
int ans=0;
for(i=1;i<=_max;i++)
if(ex[i]&&fa[i]==i)
{
ans1=0,ans2=0;
vis[i]=1,dfs(i);//两次dfs
vis[i]=0,dfs1(i);
ans+=max(ans1,ans2);//取最大的加上
}
pf("Case %d: %d\n",++ca,ans);
}
return 0;
}