AC通道:https://vijos.org/p/1221
[分析]
因为一个村民对于他(她)回答的事件A、B,都说假话或都说真话,所以它们可以看作一个事件。将可以看做一个事件的几个事件合并起来,最后统计事件的个数k,则答案数就是2^k。至于是否有解,可以用设置虚拟节点的方法解决。如果某个村民说A与B的真假不相同,而另外的村民说A与B的真假相同,则这个问题无解
#include <iostream> #include <cstdio> #include <cstring> using namespace std; struct bign{ int num[100],len; bign(int a=0){ memset(num,0,sizeof(num)); len=1; num[len]=a; } bign operator = (const char *str){ len=strlen(str); for(int i=1;i<=len;i++)num[i]=str[len-i]-'0'; return *this; } bign operator = (const int a){ char str[100]; sprintf(str,"%d",a); *this=str; return *this; } bign operator *=(const int a){ int b=0; for(int i=1;i<=len+1;i++){ num[i]=num[i]*a+b; b=num[i]/10; if(num[i]>=10){ num[i]%=10; } } if(num[len+1])len++; return *this; } void print(){ for(int i=len;i>=1;i--)printf("%d",num[i]); } }; int n,m; int fa[1000],answer; bool ans[1000]; int find(int x){ int tmp=x,pre; while(tmp!=fa[tmp])tmp=fa[tmp]; while(x!=tmp){ pre=fa[x]; fa[x]=tmp; x=pre; } return tmp; } void merge(int x,int y){ int fx=find(x),fy=find(y); fa[fx]=fy; } bign power(int a,int b){ bign ans=1; for(int i=1;i<=b;i++){ ans*=2; } return ans; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n*2;i++)fa[i]=i; for(int i=1;i<=m;i++){ int a,b,c,d; scanf("%d%d%d%d",&a,&b,&c,&d); if(b==d){ if(find(a)==find(c+n)||find(c)==find(a+n)){ printf("No Answer\n"); return 0; } merge(a,c); merge(a+n,c+n); } if(b!=d){ if(find(a)==find(c)||find(a+n)==find(c+n)){ printf("No Answer\n"); return 0; } merge(a+n,c); merge(a,c+n); } } for(int i=1;i<=n*2;i++){ans[find(i)]=true;} for(int i=1;i<=n*2;i++)answer+=ans[i]; power(2,(answer)/2).print(); return 0; }