并查集-POJ2912 Rochambeau

来源:互联网 发布:c#管理系统界面源码 编辑:程序博客网 时间:2024/05/02 02:29

题意:有n个孩子玩"石子剪刀布",有3组,每一组在每一轮游戏中的孩子出的手势是一样,但在他们其中有一个judge出的手势是随意。经过m次游戏,问你能否找出这个judge的孩子。

分析:此题是3个制约关系,很容易想到poj中食物链的那道题,也是形成3个制约关系。可以直接套公式:Rank[x]=(Rank[y]-Rank[x]+d-1+3)%3(1<=d<=3).那么怎么找出judge呢?

由于数据不大,可以对每个孩子枚举。由于judge是不满足上述的制约。所以出掉judge,上述关系依然成立。若只有一个人满足,就可以确定,输出最早能判断的游戏次数。如果有多个就不能确定输出Can not determind.如果没有一个人,输出Impossible。稍微难理解的是:怎样输出最早能确定的游戏次数?,如果号码为i的孩子所建立的制约关系在j次游戏出错,那么就是第j次游戏judge不满足,而judge都要满足,那么他就是在其他不是judge的孩子所出错最大的游戏次数,好好想想!

输入有点坑!中间没有空格。

#include<cstdio>#include<cstring>#define max(x,y) x>y?x:y;const int N=2005;int n,m,ans,Max;int father[N],Rank[N];int x[N],y[N],d[N];void Init(int n){for(int i=0;i<n;i++){father[i]=i;Rank[i]=0;}}int Find(int x){if(x==father[x]) return x;else{int tmp=father[x];father[x]=Find(tmp);Rank[x]=(Rank[x]+Rank[tmp])%3;}return father[x];}void Union(int x,int y,int d){int fx,fy;fx=Find(x);fy=Find(y);father[fx]=fy;Rank[fx]=(Rank[y]-Rank[x]+3+d)%3;}int Judge(){bool flag;int p=0,fx,fy;ans=0,Max=0;for(int i=0;i<n;i++){Init(n);flag=1;for(int j=0;j<m;j++){if(x[j]==i||y[j]==i) continue;fx=Find(x[j]),fy=Find(y[j]);if(fx==fy){if(Rank[x[j]]!=(Rank[y[j]]+d[j])%3){flag=0;Max=max(Max,j+1);break;}    }else Union(x[j],y[j],d[j]);}if(flag) p++,ans=i;if(p>1) return p;}return p;}int main(){int a,b,i,j,k;char op[10];while(scanf("%d %d",&n,&m)!=EOF){for(i=0;i<m;i++){    scanf("%s",op);    int len=strlen(op);    for(j=0;j<len;j++){if(op[j]=='='||op[j]=='<'||op[j]=='>'){if(op[j]=='=') d[i]=0;else if(op[j]=='<') d[i]=1;else d[i]=2;break;}    }    int v=0;for(k=0;k<j;k++){v=v*10+(op[k]-'0');}x[i]=v;v=0;for(k=j+1;k<len;k++){v=v*10+(op[k]-'0');}y[i]=v;}int p=Judge();if(p==0) puts("Impossible");else if(p==1) printf("Player %d can be determined to be the judge after %d lines\n",ans,Max);else puts("Can not determine");    }return 0;}