并查集+扩展域好题
题意有点模糊,意思是这里有三种人和一个判官在猜拳,每一种人只能出一种手势,这里面有一个判官可以随意改变自己的手势!给定m个回合判断,问判官是谁。能知道就输出最快能在第几回合清楚,如果多了就输出“Can not determine”,或者不存在就是“Impossible”。
分析:
数据很小,可以暴力枚举每一个人,如果n个人里面除开这个人以外,其余所有人都不冲突,则这个人就可能是判官,最后数一下有几个这样的人就好了,如果刚好只有一个,那么我们只需注意最快的回合;明显其余人不可能是判官的条件是出现了冲突,那么我们只需要输出其余所有人中冲突出现最晚的那个人就好了!
上代码:
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<string.h>
using namespace std;
const int N = 5e2+5;
typedef long long ll;
// 0代表小于,1代表大于,2代表等于,判别方式(3-x)%3;
// 当每一次出现规则冲突时记录冲突数字,
int f[N],d[N],s[N];
int get(int x){
if(f[x]==x){
return x;
}
int cur=get(f[x]);
d[x]=(d[x]+d[f[x]])%3;
return f[x]=cur;
}
bool join(int p,int q, int fg){
int l=get(p),r=get(q);
if(l==r){
if((d[p]+fg)%3==d[q]) return true;//网上大佬判冲突的。。。
/*
if(fg==0){
if(d[p]==d[q]) return true;
}
else if(fg==1){
if(d[p]==2&&d[q]==0) return true;
if(d[p]==1&&d[q]==2) return true;
if(d[p]==0&&d[q]==1) return true;
}
else{
if(d[p]==1&&d[q]==0) return true;
if(d[p]==2 &&d[q]==1) return true;
if(d[p]==0&&d[q]==2) return true;
}
*/ //这个是我冲突。。。
return false;
}
else{
f[r]=l;
d[r]=(fg+3-d[q]+d[p])%3;
return true;
}
}
int main()
{
int n,m,i,j,k;
char b[2001];
int a[2001],c[2001];
while(scanf("%d %d",&n,&m)==2){
if(m==0){
if(n==1){
printf("Player 0 can be determined to be the judge after 0 lines\n");
}
else printf("Can not determine\n");
continue;
}
int flag=0,ans=-1,pos=-1,cnt=0,kk=0;
for(i=0;i<=n;i++) f[i]=i,d[i]=0;
for(i=1;i<=m;i++){
scanf("%d%c%d",&a[i],&b[i],&c[i]);
}
for(i=0;i<n;i++){
for(k=0;k<=n;k++) f[k]=k,d[k]=0;
cnt=0;
for(j=1;j<=m;j++){
if(b[j]=='=') k=0;
else if(b[j]=='>') k=1;
else k=2;
if(a[j]==i||c[j]==i) continue;
if(!join(a[j],c[j],k)){
cnt++;
pos=max(pos,j);
break;
}
}
kk+=(cnt==0);
if(cnt==0) ans=i;
}
if(kk==0){
printf("Impossible\n");
}
else{
if(kk>1){
printf("Can not determine\n");
}
else{
printf("Player %d can be determined to be the judge after %d lines\n",ans,pos);
}
}
}
return 0;
}
自言自语
最近算法忘得有点狠,这个寒假集训就用来复习算了,这是寒假第一题,并查集写wa了,正确的并查集扩展域写法应该是先递归到最底层然后一路向上更新路径,而正确的并查集边带权则是