神奇配方[VIJOS1221]

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; 
}


你可能感兴趣的:(编程)