Gym 101128 B Black Vienna

Posted 蒟蒻LQL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gym 101128 B Black Vienna相关的知识,希望对你有一定的参考价值。

题意

有A-Z 26张牌,现在从中抽出3张牌,并把剩下的23张牌分给选手1和2,现在有n次询问,每次询问一个选手是否有某两张牌,和选手的回答。回答说自己有这两张牌中的几张,问拿出的三张牌有多少种方案能够满足这n个条件?n<=50

分析

个人感觉这个题是个很不错的题呢。

并查集的应用,有点像那道“关押罪犯”的升级版?www.cnblogs.com/LQLlulu/p/8819599.html

数据很小,只有26张牌和50个询问。那么三重循环枚举抽哪三张牌。对于每次抽出的三张牌,判断一下能否满足这n个询问,如果满足的话ans++。

但是怎么判断?

因为只有两个玩家,那么对于每张牌,如果这张牌没有被抽走,那么要么属于玩家1,要么属于玩家2。对于大多数情况我们都可以通过记录每张牌的归属判断是否冲突。

但是有一种特殊情况:

此时两张牌都未被抽走,而且回答是1。也就是说,这两张牌里有一张是属于这个人,另一张属于另一个玩家。那么我们此时没法直接记录。因为我们并不能知道哪张牌属于谁,只能确定这两张牌不属于同一个人!没错!这句话表明了要用并查集!

对于每个上述的情况:x=find(a),y=find(b),如果x和y相等说明两者在同一个人手中,那么直接返回false,否则的话我们把他们和另一个的补集相连,p[x]=find(b+n),p[y]=find(a+n)。这代表两者不在同一个集合(因为只有两个集合,所以满足敌人的敌人就是朋友)。

然后对于每个并查集就分给一个人,判断是否会冲突,如果冲突返回false。

如果上述都没有冲突,则返回true。

 

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 #include <iostream>
  5 
  6 using namespace std;
  7 const int maxn=100+10;
  8 int n;
  9 int p[maxn];
 10 struct Node{
 11     char s[2];
 12     int who;
 13     int num;
 14 }node[maxn];
 15 int ans;
 16 int Wh[maxn],val[maxn];
 17 int find(int x){
 18     return p[x]==x?x:p[x]=find(p[x]);
 19 }
 20 bool check(int A,int B,int C){
 21     for(int i=1;i<=60;i++)p[i]=i;
 22     memset(Wh,-1,sizeof(Wh));
 23     bool ok=1;
 24     for(int i=1;i<=n;i++){
 25         int a=node[i].s[0]-\'A\'+1;
 26         int b=node[i].s[1]-\'A\'+1;
 27         int w=node[i].who;
 28       //  cout<<a<<" "<<b<<" "<<node[i].num<<endl;
 29 
 30         if(node[i].num==2){
 31             if(a==A||a==B||a==C||b==A||b==B||b==C){
 32                 //cout<<"-1"<<endl;
 33                 ok=0;
 34                 break;
 35             }
 36             if((Wh[a]==(w^1))||(Wh[b]==(w^1))){
 37                 ok=0;
 38                 break;
 39             }
 40            // cout<<-1<<endl;
 41             Wh[a]=w,Wh[b]=w;
 42         }
 43         if(node[i].num==0){
 44             if((a==A||a==B||a==C)&&(b==A||b==B||b==C))
 45                 continue;
 46             else if(a==A||a==B||a==C){
 47                 if(Wh[b]==w){
 48                     ok=0;
 49                     break;
 50                 }
 51                 Wh[b]=(w^1);
 52             }
 53             else if(b==A||b==B||b==C){
 54                 if(Wh[a]==w){
 55                     ok=0;
 56                     break;
 57                 }
 58                 Wh[a]=(w^1);
 59             }
 60             else{
 61                 if(Wh[a]==w||Wh[b]==w){
 62                     ok=0;
 63                     break;
 64                 }
 65                 Wh[a]=(w^1),Wh[b]=(w^1);
 66             }
 67         }
 68         if(node[i].num==1){
 69             if((a==A||a==B||a==C)&&(b==A||b==B||b==C)){
 70                 ok=0;
 71                 break;
 72             }
 73             else if(a==A||a==B||a==C){
 74                 if(Wh[b]==(w^1)){
 75                     ok=0;
 76                     break;
 77                 }
 78                 Wh[b]=w;
 79             }
 80             else if(b==A||b==B||b==C){
 81                 if(Wh[a]==(w^1)){
 82                     ok=0;
 83                     break;
 84                 }
 85                 Wh[a]=w;
 86             }else{
 87                 int x=find(a),y=find(b);
 88                 if(x==y){
 89                     ok=0;
 90                     break;
 91                 }
 92                 p[x]=find(b+26);
 93                 p[y]=find(a+26);
 94             }
 95         }
 96     }
 97     if(!ok)return false;
 98 
 99     memset(val,-1,sizeof(val));
100     for(int i=1;i<=26;i++){
101         if(Wh[i]!=-1){
102             int f=find(i);
103             if(val[f]==
104                (Wh[i]^1)){
105                 ok=0;
106               //  cout<<-1<<endl;
107                 break;
108             }
109             val[f]=Wh[i];
110             f=find(i+26);
111            // cout<<Wh[i]<<endl;
112             if(val[f]==Wh[i]){
113                // cout<<val[f]<<" "<<Wh[i]<<endl;
114                 ok=0;
115                 break;
116             }
117             val[f]=(Wh[i]^1);
118         }
119     }
120     if(!ok)return false;
121 
122     for(int i=1;i<=26;i++){
123         int x=find(i),y=find(i+26);
124         if(x==y||(val[x]==val[y]&&val[x]!=-1)){
125             ok=0;
126             break;
127         }
128     }
129     if(!ok)return false;
130     return true;
131 }
132 int main(){
133     ans=0;
134     scanf("%d",&n);
135     for(int i=1;i<=n;i++){
136         scanf("%s%d%d",node[i].s,&node[i].who,&node[i].num);
137         node[i].who--;
138     }
139 
140     for(int i=1;i<=26;i++){
141         for(int j=i+1;j<=26;j++){
142             for(int k=j+1;k<=26;k++){
143                 if(check(i,j,k))
144                     ans++;
145             }
146         }
147     }
148     cout<<ans;
149 return 0;
150 }
View Code

 

以上是关于Gym 101128 B Black Vienna的主要内容,如果未能解决你的问题,请参考以下文章

GYM 101128 J.Saint John Festival(求凸包是否包含点)

很好的脑洞题:dfs+暴力 Gym - 101128A Promotions

Gym 101128F Sheldon Numbers(网络流)

dp+分类讨论 Gym 101128E

Saint John Festival Gym - 101128J (凸包二分)

Game of Cards Gym - 101128G (SG函数)