GYM 101128 B.Black Vienna(并查集)
来源:互联网 发布:虚拟机运行ubuntu很卡 编辑:程序博客网 时间:2024/05/29 07:41
Description
有A~Z这26张牌,现在从中抽出三张并把剩余23张分给选手1和2,现在有n次查询,每次询问一个选手是否有某两张牌,和选手的回答,回答是说自己有这两张牌中的几张,问拿出的三张牌有多少种方案能够满足这n个条件
Input
第一行一整数n表示查询数,每组查询输入两个字符表示要查询的两张牌,以及要查询的选手编号(1or2),以及选手的回答(0,1,2)表示这两张牌手里有多少张(0<=n<=50)
Output
输出合法方案数
Sample Input
3
AB 1 1
AC 2 1
BC 2 1
Sample Output
506
Solution
首先处理0张和2张的情况,遇见不合法情况直接gg,那么剩下的就是1张的情况,枚举拿出的三张牌用并查集判是否合法,i表示1选手拿第i张牌,i+26表示2选手拿第i张牌,0表示一定拿,53表示一定拿,对于拿出的三张牌x,y,z,如果某位选手拿了则不合法,没有则两位选手都不拿这三张牌,之后处理1张查询中涉及到x,y,z这三张牌的查询,设这次查询问的是a,b,如果a,b都属于这三张牌则gg;如果没有属于这三种牌的则把1拿a和2拿b合并,2拿a和1拿b合并;如果a,b有一张属于这三张牌,那么该选手一定拿另一张牌,不妨另一张牌是b,那么就是当前选手一定拿b另一选手一定不拿b,这样就处理完1张的查询,然后处理除x,y,z之外某些被确定拿或不拿的牌,如果i牌两个人都一定不拿或一定拿则gg,如果一张牌1一定拿2一定不拿,则把i和0合并,i+26和53合并,如果1一定不拿2一定拿,则把i和53合并,i+26和0合并,所有合并操作结束,判断fa[i]和fa[i+26]是否相同,如果相同说明两位选手拿了同一张牌,不合法;然后判断fa[0]和fa[53]是否相同,如果相同说明一位选手拿某张牌又不拿某张牌才会把0和53合并,不合法;否则合法
Code
#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#include<cmath>#include<queue>#include<stack>#include<map>#include<vector>#include<string>using namespace std;#define maxn 55int fa[maxn];void init(int n){ for(int i=0;i<=n;i++)fa[i]=i;}int find(int x){ if(fa[x]==x)return x; return fa[x]=find(fa[x]);}void unite(int x,int y){ x=find(x),y=find(y); if(x==y)return ; fa[x]=y; }int n,q[55][3],res,vis[2][33],mark[2][33],used[55];char op[5];bool check(int x,int y,int z){ init(53); for(int i=0;i<2;i++) for(int j=1;j<=26;j++) mark[i][j]=vis[i][j]; for(int i=0;i<2;i++) { if(mark[i][x]==1||mark[i][y]==1||mark[i][z]==1)return 0; mark[i][x]=mark[i][y]=mark[i][z]=-1; } for(int i=1;i<=res;i++) { int f1=0,f2=0,a=q[i][0],b=q[i][1],c=q[i][2]; if(b==x||b==y||b==z)f1=1; if(c==x||c==y||c==z)f2=1; if(f1&&f2)return 0; if(f2)swap(b,c),swap(f1,f2); if(f1) { int t1=a*26+c,t2=(a^1)*26+c; unite(t1,0),unite(t2,53); } else { int t1=a*26+b,t2=a*26+c,t3=(a^1)*26+b,t4=(a^1)*26+c; unite(t1,t4),unite(t2,t3); } } for(int i=1;i<=26;i++) if(i!=x&&i!=y&&i!=z) { if(mark[0][i]==1&&mark[1][i]==1)return 0; if(mark[0][i]==-1&&mark[1][i]==-1)return 0; if(mark[0][i]==1||mark[1][i]==-1)unite(i,0),unite(26+i,53); else if(mark[1][i]==1||mark[0][i]==-1)unite(i,53),unite(26+i,0); } if(fa[0]==fa[53])return 0; for(int i=1;i<=26;i++) if(fa[i]==fa[i+26])return 0; return 1;}int main(){ while(~scanf("%d",&n)) { res=0; memset(vis,0,sizeof(vis)); int gg=0; for(int i=1;i<=n;i++) { int a,b; scanf("%s%d%d",op,&a,&b); a--; int c=op[0]-'A'+1,d=op[1]-'A'+1; if(c>d)swap(c,d); if(b==0) { if(vis[a][c]==1||vis[a][d]==1)gg=1; else vis[a][c]=vis[a][d]=-1; } else if(b==2) { if(vis[a][c]==-1||vis[a][d]==-1)gg=1; else vis[a][c]=vis[a][d]=1; } else q[++res][0]=a,q[res][1]=c,q[res][2]=d; } int ans=0; if(!gg) { for(int i=1;i<=26;i++) for(int j=i+1;j<=26;j++) for(int k=j+1;k<=26;k++) if(check(i,j,k))ans++; } printf("%d\n",ans); } return 0;}
- GYM 101128 B.Black Vienna(并查集)
- GYM 100971 A.Treasure Island(dfs+并查集)
- 南邮 OJ 1091 Black Vienna
- GYM 100685 G【并查集】
- Gym 100703J 并查集
- Problem B. Black and White Gym-100801B] 想象力
- GYM 101173 H.Hangar Hurdles(并查集+bfs+dfs)
- Codeforces Gym 101173 H. Hangar Hurdles (LCA + 并查集)
- Gym 100712F Travelling Salesman(二分+并查集)
- Codeforces Gym 100814C Connecting Graph (并查集, 树链剖分)
- Gym - 100625G Getting Through 计算几何+并查集
- GYM 101243 F.Vitamins【思维+并查集】
- NEU 1293: Gang Black and Gang White 并查集
- HDU 1312 Red and Black(并查集或者BFS)
- (并查集)B - Friends(8.4.1)
- poj 1611(并查集)(B)
- CodeForces 445B. DZY Loves Chemistry(并查集)
- CF 547 B. Mike and Feet(并查集)
- hduoj-5666【快速乘&&规律】
- 对hog中的三次线性插值的一点解释(转)
- sp_msforeachdb
- 调整数组顺序使奇数位于偶数前面
- CSS3笔记1 — 文字阴影、边框阴影、自动换行
- GYM 101128 B.Black Vienna(并查集)
- 重载
- NOIP2011
- 2002 计算球体积
- java中的各种数据类型在内存中存储的方式
- java类与对象
- 【杭电】5666 快乘
- localStorage的使用
- HOG特征中的三线插值法