题意:有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;
}