并查集-POJ2912 Rochambeau

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值