POJ-2912-Rochambeau
题目大意: N 个孩子们正在和你玩 “ 剪刀石头布 ” 游戏,其中一位是法官。其余的孩子分为三组(可能有一组是空的)。
你不知道谁是法官,也不知道孩子们是如何分组的。然后孩子们开始玩 \(Rochambeau\) 游戏 \(M\) 轮。每轮两个孩子被任意选择玩一次,你会被告知结果,但是你不知道孩子们做了什么手势。
同一组中的孩子会表现出相同的手势,不同的组会表现出不同的手势。
法官每次都会随机做出手势,因此没有人知道法官会做出什么手势。
比赛结束后,你能猜出谁是裁判吗?如果可以的话,你最早能在几轮之后找到法官
思路
并查集的拓展域或者边带权,十分类似于食物链这道题
每个人有三个部分:赢自己的人,自己赢的人,和自己出同样手势的人
如果这两个人 “ = ” ,就分别合并他们的三个集合
如果小于或者大于就像这样(统一把所有的 \(>\) 变成 \(<\) ):
int fa[N*3];//同族,输给了谁,赢了谁
mer(a[j],b[j]+n*2),mer(a[j]+n,b[j]),mer(a[j]+n*2,b[j]+n);
枚举每个人为法官的时候,去掉所有与其相关的来判断有没有矛盾。如果有多个不产生矛盾的就为 Can not determine
,如果一个都没有就是 Impossible
。
至于找可判断出的行数就在判断过程中记录非裁判,出现矛盾的最大行数即为答案。
$Code$
#include<iostream>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<stdio.h>
using namespace std;
const int N=505,M=2005;
int fa[N*3],a[M],b[M],ed[M];//同族,输给了谁,赢了谁
int n,m;
void unit(){
for(int i=1;i<=n*3;++i) fa[i]=i;
}
int fi(int x){
if(fa[x]==x) return x;
return fa[x]=fi(fa[x]);
}
void mer(int x,int y){
fa[fi(x)]=fi(y);
}
void sol(){
for(int i=1;i<=m;++i){
int x,y;char c;
cin>>x>>c>>y;++x,++y;
if(c=='>') swap(x,y);
a[i]=x,b[i]=y;
if(c=='=') ed[i]=0;
else ed[i]=1;//<
}
if(n==1){
printf("Player 0 can be determined to be the judge after 0 lines\n");
return;
}
int mrk=-1,ju=0,ans=-1;
for(int i=1;i<=n;++i){
unit();int cnt=0,is=0;
for(int j=1;j<=m;++j){
if(a[j]==i || b[j]==i) continue;
else{
if(!ed[j]){
if(fi(a[j])==fi(b[j]+n) || fi(a[j]+n)==fi(b[j])){
is=-2,ans=max(ans,j);
break;
}
mer(a[j],b[j]),mer(a[j]+n,b[j]+n),mer(a[j]+n*2,b[j]+n*2);
}
if(ed[j]){
if(fi(a[j])==fi(b[j]) || fi(a[j]+n*2)==fi(b[j])){
is=-2,ans=max(ans,j);
break;
}
mer(a[j],b[j]+n*2),mer(a[j]+n,b[j]),mer(a[j]+n*2,b[j]+n);
}
}
}
if(is==-2) continue;
if(ju){
mrk=-2;break;
}
ju=i;
}
if(ju && mrk!=-2) printf("Player %d can be determined to be the judge after %d lines\n",ju-1,ans);
else if(mrk==-2) cout<<"Can not determine"<<endl;
else cout<<"Impossible"<<endl;
}
int main(){
while(cin>>n>>m) sol();
return 0;
}