首先我们会发现所有的人构成了一个图
定义相爱为 在一个集合里
定义相恨为 不在一个集合里
很容易发现满足条件的图一定是一个二分图
那么分类讨论如下:
1、如果出现不合法 答案为0
2、如果不是一个二分图 答案为0
3、设图中联通块有k个,那么答案为2^k/2! = 2^(k-1)
那么算法很明了了
将相爱的人用并查集缩点并判断不合法
之后相恨的人之间相互连边并进行二分图染色判定
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> using namespace std; typedef long long LL; const int maxn=100010; const int mod=1e9+7; int n,m; int co[maxn]; struct Edge{ int u,v,type; }c[maxn]; int h[maxn],cnt=0; int fa[maxn]; struct edge{ int to,next; }G[maxn<<2]; int ufs(int x){return fa[x]==x?x:fa[x]=ufs(fa[x]);} void add(int x,int y){++cnt;G[cnt].to=y;G[cnt].next=h[x];h[x]=cnt;} LL pow_mod(LL v,int p){ LL tmp=1; while(p){ if(p&1)tmp=tmp*v%mod; v=v*v%mod;p>>=1; }return tmp; } bool paint(int u){ for(int i=h[u];i;i=G[i].next){ int v=G[i].to; if(co[v]){ if(co[v]==co[u])return false; }else{ co[v]=3-co[u]; if(!paint(v))return false; } }return true; } int Get_color(){ int ans=0; for(int i=1;i<=n;++i){ if(ufs(i)!=i)continue; if(co[i])continue; ans++;co[i]=1; if(!paint(i))return -1; }return ans; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;++i)scanf("%d%d%d",&c[i].u,&c[i].v,&c[i].type); for(int i=1;i<=n;++i)fa[i]=i; for(int i=1;i<=m;++i){ if(c[i].type){ int d1=ufs(c[i].u),d2=ufs(c[i].v); if(d1!=d2)fa[d1]=d2; } } for(int i=1;i<=m;++i){ if(!c[i].type){ int d1=ufs(c[i].u),d2=ufs(c[i].v); if(d1==d2){printf("0 ");return 0;} add(d1,d2);add(d2,d1); } } int k=Get_color(); if(k==-1)printf("0 "); else printf("%I64d ",pow_mod(2LL,k-1)); return 0; }