题意
n个人玩石头剪刀布的游戏,其中有一个人是裁判,要求将这些人分成三组,这三组可以为空,然后如果裁判为1个输出裁判为第几个人,在多少行就判断出来,如果裁判可能有多个,就输出"Can not determine",没有就输出"Impossible".
思路
种类并查集(雾),我之前都做的是扩展域并查集,然而我是看完题解才懂的,并查集貌似是满足以下图片的关系,图片参考的博客
看着自己YY一下,感觉还挺有道理,主要是这个关系其实是构成一个环,石头>剪刀,剪刀>布,然后布>石头,然后取模就可以得到与父节点的关系.
代码
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
struct node{
int x,y;
char c;
}a[maxn];
int fa[maxn],rel[maxn];
int f(char c){
if(c=='=') return 0;
if(c=='<') return 1;
if(c=='>') return 2;
}
int find(int x){
if(x==fa[x]) return x;
int fx=find(fa[x]);
rel[x]=(rel[x]+rel[fa[x]])%3;
return fa[x]=fx;
}
bool check(int x,int y,int flag){
int fx=find(x),fy=find(y);
if(fx!=fy){
fa[fx]=fy;
rel[fx]=(3+flag+rel[y]-rel[x])%3;
return true;
}
else return flag==(3+rel[fx]+rel[x]-rel[y])%3;
}
int main(){
int n,m;
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=m;i++){
scanf("%d%c%d",&a[i].x,&a[i].c,&a[i].y);
}
int ans=0,id,maxx=0;
for(int i=0;i<n;i++){
bool flag=0;
for(int i=0;i<n;i++) fa[i]=i,rel[i]=0;
for(int j=1;j<=m;j++){
if(i==a[j].x||i==a[j].y) continue;
if(!check(a[j].x,a[j].y,f(a[j].c))){
flag=1;
maxx=max(maxx,j);
break;
}
}
if(!flag){
id=i;
ans++;
}
}
if(ans>1) printf("Can not determine\n");
else if(ans==1) printf("Player %d can be determined to be the judge after %d lines\n",id,maxx);
else printf("Impossible\n");
}
}