1. 程式人生 > >Gym 101128 B Black Vienna

Gym 101128 B Black Vienna

說明 另一個 cstring eve 方案 www. pen name space

題意

有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