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;}
0 0
原创粉丝点击