题面链接
https://www.luogu.com.cn/problem/P1892
题解
-
暴力:
我首先想到的是邻接矩阵的乘法:把二次的敌人矩阵并入朋友矩阵,然后求出 a n s ( n , n ) = ∑ i = 1 n f r i e n d ( n , n ) i ans(n,n)=\sum_{i=1}^{n} friend(n,n)^i ans(n,n)=i=1∑nfriend(n,n)i
这个ans矩阵就是所有的朋友关系邻接矩阵了。然后邻接矩阵上跑个连通分量就完了。这样n次矩阵乘法复杂度 O ( n 4 ) O(n^4) O(n4)。万万不能接受。 -
正解并查集
经典并查集算法。把点i拆成i和i+n两个点。如果i,j朋友,就合并i,j。敌人就分别合并i+n,j和i,j+n。这样敌人的敌人就会在同一个集合里。最后答案就是1-n中的集合总个数。复杂度θ(n+m)。
AC代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int NN=1100;
int fa[NN<<1];
int f[NN<<1];
int get_fa(int x){
if(fa[x]==x)return x;
return (fa[x]=get_fa(fa[x]));
}
void merg(int x,int y){
int fax=get_fa(x);
int fay=get_fa(y);
if(fax!=fay){
fa[fax]=fay;
}
}
int main(){
int n,m;scanf("%d%d",&n,&m);
for(int i=1;i<=n<<1;i++)fa[i]=i;
for(int i=1;i<=m;i++){
int x,y;
char s[3];
scanf("%s%d%d",s,&x,&y);
if(s[0]=='F'){
merg(x,y);
}
else{
merg(x+n,y);
merg(x,y+n);
}
}
for(int i=1;i<=n;i++){
f[get_fa(i)]=1;
}
int ans=0;
for(int i=1;i<=n<<1;i++)ans+=f[i];
printf("%d\n",ans);
return 0;
}
结果
不开O2的情况下: