poj2912Rochambeau 枚举+带权并查集

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;
 }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值