• 【并查集】Gym


    有26张牌(A~Z),其中三张被拿走了。其余23张被分发给了两个人。给你m次调查结果,一次调查结果是对其中一个人询问一对牌,他会告诉你他有这对牌的几张(0~2)。问你有多少种被拿走的牌的组合。

    三重循环枚举被拿走的牌。

    然后对于一次调查,我们发现可能的十二种情况中({这两张牌都被拿走,都不被,其中一张被拿走,其中另一张被拿走} × {回答:0,1,2}),只有一种情况我们不能确定它们的归属,或者无解。即两张牌都不被拿走,并且回答是1。那么必然其中一张牌在一个人手上,另一张牌在另一人手上,但我们不能确定是那张。

    其实这是个2-sat的XOR。

    因为是双向边,我们可以直接用并查集。

    然后有些牌的归属在一开始就已经被制定了。

    如果A和!A在同一个并查集里边或者其并查集的取值都一开始确定,并且两者相同,那么无解。其他都有解。

    #include<cstdio>
    #include<cstring>
    using namespace std;
    int n,whi[55],xs[55],ans;
    char op[55][4];
    bool cho[105];
    int beg[105];
    int fa[105],val[105];
    int find(int x){
    	return x==fa[x] ? x : fa[x]=find(fa[x]);
    }
    int main(){
    //	freopen("b.in","r",stdin);
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i){
    		scanf("%s%d%d",op[i],&whi[i],&xs[i]);
    		--whi[i];
    	}
    	for(int i='A';i<='Z';++i){
    		for(int j=i+1;j<='Z';++j){
    			for(int k=j+1;k<='Z';++k){
    				memset(beg,-1,sizeof(beg));
    				memset(val,-1,sizeof(val));
    				for(int p=1;p<=52;++p){
    					fa[p]=p;
    				}
    				cho[i]=cho[j]=cho[k]=1;
    				bool flag=1;
    				for(int p=1;p<=n;++p){
    					if(cho[op[p][0]] && cho[op[p][1]]){
    						if(xs[p]>=1){
    							flag=0;
    							break;
    						}
    					}
    					else if(cho[op[p][0]]){
    						if(xs[p]==0){
    							if(beg[op[p][1]]==whi[p]){
    								flag=0;
    								break;
    							}
    							beg[op[p][1]]=(whi[p]^1);
    						}
    						else if(xs[p]==1){
    							if(beg[op[p][1]]==(whi[p]^1)){
    								flag=0;
    								break;
    							}
    							beg[op[p][1]]=whi[p];
    						}
    						else{
    							flag=0;
    							break;
    						}
    					}
    					else if(cho[op[p][1]]){
    						if(xs[p]==0){
    							if(beg[op[p][0]]==whi[p]){
    								flag=0;
    								break;
    							}
    							beg[op[p][0]]=(whi[p]^1);
    						}
    						else if(xs[p]==1){
    							if(beg[op[p][0]]==(whi[p]^1)){
    								flag=0;
    								break;
    							}
    							beg[op[p][0]]=whi[p];
    						}
    						else{
    							flag=0;
    							break;
    						}
    					}
    					else{
    						if(xs[p]==0){
    							if(beg[op[p][0]]==whi[p] || beg[op[p][1]]==whi[p]){
    								flag=0;
    								break;
    							}
    							beg[op[p][0]]=beg[op[p][1]]=(whi[p]^1);
    						}
    						else if(xs[p]==2){
    							if(beg[op[p][0]]==(whi[p]^1) || beg[op[p][1]]==(whi[p]^1)){
    								flag=0;
    								break;
    							}
    							beg[op[p][0]]=beg[op[p][1]]=whi[p];
    						}
    						else{
    							int f1=find(op[p][0]-'A'+1),f2=find(op[p][1]-'A'+1+26);
    							fa[f1]=f2;
    							f1=find(op[p][0]-'A'+1+26),f2=find(op[p][1]-'A'+1);
    							fa[f2]=f1;
    						}
    					}
    				}
    				if(flag){
    //					if(i=='X' && j=='Y' && k=='Z'){
    //						i='X';
    //					}
    					for(int p='A';p<='Z';++p){
    						if(beg[p]!=-1){
    							int f=find(p-'A'+1);
    							if(val[f]==(beg[p]^1)){
    								flag=0;
    								break;
    							}
    							else{
    								val[f]=beg[p];
    							}
    							
    							f=find(p-'A'+1+26);
    							if(val[f]==beg[p]){
    								flag=0;
    								break;
    							}
    							else{
    								val[f]=(beg[p]^1);
    							}
    						}
    					}
    					if(flag){
    						for(int p='A';p<='Z';++p){
    							int f1=find(p-'A'+1),f2=find(p-'A'+1+26);
    							if(f1==f2 || (val[f1]==val[f2] && val[f1]!=-1)){
    								flag=0;
    								break;
    							}
    						}
    						if(flag){
    							++ans;
    						}
    					}
    				}
    				cho[i]=cho[j]=cho[k]=0;
    			}
    		}
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
  • 相关阅读:
    Linux 文件特殊权限
    Linux ACL权限
    Linux 用户管理命令
    Asm.js: Javascript的编译目标
    《Zero to One》的一些读书笔记
    Tomcat架构(四)
    Tomcat架构(三)
    Tomcat架构(二)
    Tomcat 架构 (一)
    MATERIAL DESIGN学习笔记
  • 原文地址:https://www.cnblogs.com/autsky-jadek/p/7296641.html
Copyright © 2020-2023  润新知