题目链接:Problem - D - Codeforces The Number of Imposters
n个人,一共有m个描述,每个表述为i认为j是好人或者是坏人,求可能的最大的坏人数。考虑并查集,并查集里面有一个典中典的题,叫食物链,类似的,利用并查集来判断是否满足条件。对于每一个人i,并查集f[i]和f[i+n]分别表示与 i是同类和异类的集合。建图参考如下代码。如果i认为j是好人那么i与j的类型是相同的,反正是不同的。如果满足条件所有的n个人会被分成若干个连通块,单独的考虑每一个连通块,按照好人与坏人中的极大值进行加权最终可计算出答案。
#include<bits/stdc++.h> const int N=2e5+5; using namespace std; int f[N<<1],T,n,m,cnt=0,sum=0; bool vs[N<<1]; vector<int> g[N<<1]; int find(int x){ if(f[x]==x) return x; return f[x]=find(f[x]); } void merge(int u,int v){ if(find(u)!=find(v)) f[find(u)]=find(v); } int dfs(int fa,int u){ if(vs[u]) return 0; vs[u]=true; if(u>n) cnt++; int res=1; for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(v==fa) continue; res+=dfs(u,v); } return res; } int main(){ scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); for(int i=1;i<=2*n;i++){//初始化 f[i]=i,vs[i]=false; g[i].clear(); } int flag=false; for(int i=1,x,y;i<=m;i++){ char s[15]; scanf("%d%d %s",&x,&y,s); if(s[0]=='i'){ merge(x+n,y); merge(x,y+n); g[x].push_back(y+n);//建图 g[y+n].push_back(x); g[y].push_back(x+n); g[x+n].push_back(y); } else { merge(x,y); merge(x+n,y+n); g[x].push_back(y);//建图 g[y].push_back(x); g[x+n].push_back(y+n); g[y+n].push_back(x+n); } } for(int i=1;i<=n;i++){ if(find(i)==find(i+n)){ flag=true; break; } } int ans=0; if(flag) printf("-1\n"); else{ for(int i=1;i<=n;i++){ if(!vs[i]&&!vs[i+n]){ cnt=0,sum=dfs(0,i); ans+=max(cnt,sum-cnt); } } printf("%d\n",ans); } } return 0; }