http://poj.org/problem?id=2912
题意:类似剪刀石头布,每个人只能出一个手势,有一个裁判可以出任意手势,给你很多个回合记录,问能否确定出来那一个裁判,如果能最少需要多少个回合
关键思路是枚举每一个人作为裁判,这样所有和他相关的回合都不考虑,看其余回合是否发生矛盾(裸的带权并查集判断),如果发生矛盾,则说明他不是裁判,裁判是别人,如果不发生矛盾,则说明他有可能是裁判,这样记录一下,如果可能是裁判的人数是1,那毫无疑问就是他,如果大于1则"Can not determine",如果小于1说明没有人可能是裁判,则"Impossible"。确定某个人是裁判后依旧不好判断最少需要的回合,这里的思维很巧妙
因为裁判只有一个,所以k是裁判的一个充要条件是除了k之外的所有人都不是裁判,刚刚在判断的时候可以记录上判断某个人不是裁判需要的最少回合,最后对所有不是裁判的取个max即可
参考博客:http://www.cnblogs.com/kuangbin/archive/2013/04/05/3001668.html
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<vector>
#define eps 1e-9
#define PI 3.141592653589793
#define bs 1000000007
#define bsize 256
#define MEM(a) memset(a,0,sizeof(a))
typedef long long ll;
using namespace std;
int f[1000],r[1000],book[2500];
void init(int x)
{
for(int i=0;i<=x;i++)
f[i]=i,r[i]=0;
}
int find_(int x)
{
if(f[x]==x)
return x;
int fa=find_(f[x]);
r[x]=(r[x]+r[f[x]])%3;
return f[x]=fa;
}
int fun(char c)
{
if(c=='=')
return 0;
else if(c=='>')
return 1;
else
return 2;
}
struct node
{
int u,v;
int f;
}q[2005];
int main()
{
int n,m,i,j,t1,t2,rea1,rea2,k;
while(cin>>n>>m)
{
memset(book,0,sizeof(book));
int cnt=0,u,v;
char c;
int ans=-1,ans1=0;
for(i=0;i<m;i++)
{
node temp;
scanf("%d%c%d",&u,&c,&v);
temp.u=++u,temp.v=++v;
temp.f=fun(c);
q[i]=temp;
}
for(i=1;i<=n;i++)
{
init(n);
for(j=0;j<m;j++)
{
if(q[j].u==i||q[j].v==i);
else
{
u=q[j].u,v=q[j].v;
t1=find_(u);
t2=find_(v);
if(t1!=t2)
{
f[t2]=t1;
r[t2]=((r[u]-r[v])%3+3+q[j].f)%3;
}
else
{
if(((r[v]-r[u])%3+3)%3!=q[j].f)
{
book[i]=j+1;
break;
}
}
}
}
}
for(i=1;i<=n;i++)
{
if(book[i]==0)
{
cnt++;
ans=i;
}
else
ans1=max(ans1,book[i]);
}
if(cnt==0)
cout<<"Impossible"<<endl;
else if(cnt>1)
cout<<"Can not determine"<<endl;
else
{
printf("Player %d can be determined to be the judge after %d lines\n",ans-1,ans1);
}
}
return 0;
}