《算法竞赛进阶指南》0x49 T2 Rochambeau

题目描述

N 个小朋友(编号为 0,1,2,…,N−1)一起玩石头剪子布游戏。

其中一人为裁判,其余的人被分为三个组(有可能有一些组是空的),第一个组的小朋友只能出石头,第二个组的小朋友只能出剪子,第三个组的小朋友只能出布,而裁判可以使用任意手势。

你不知道谁是裁判,也不知道小朋友们是怎么分组的。

然后,孩子们开始玩游戏,游戏一共进行 M 轮,每轮从 N 个小朋友中选出两个小朋友进行猜拳。

你将被告知两个小朋友猜拳的胜负结果,但是你不会被告知两个小朋友具体使用了哪种手势。

比赛结束后,你能根据这些结果推断出裁判是谁吗?

如果可以的话,你最早在第几轮可以找到裁判。

输入格式

输入可能包含多组测试用例

每组测试用例第一行包含两个整数 N 和 M。

接下来 M 行,每行包含两个整数 a,b,中间夹着一个符号(>,=,<),表示一轮猜拳的结果。

两个整数为小朋友的编号,a>b 表示 a 赢了 b,a=b 表示 a 和 b 平手,a

输出格式

每组测试用例输出一行结果,如果找到裁判,且只能有一个人是裁判,则输出裁判编号和确定轮数。

如果找到裁判,但裁判的人选多于 1 个,则输出 Can not determine。

如果根据输入推断的结果是必须没有裁判或者必须有多个裁判,则输出 Impossible。

具体格式可参考样例。

数据范围

1 ≤ N ≤ 500 , 1≤N≤500, 1N500,
0 ≤ M ≤ 2000 0≤M≤2000 0M2000

输入样例:

3 3
0<1
1<2
2<0
3 5
0<1
0>1
1<2
1>2
0<2
4 4
0<1
0>1
2<3
2>3
1 0

输出样例:

Can not determine
Player 1 can be determined to be the judge after 4 lines
Impossible
Player 0 can be determined to be the judge after 0 lines

题解

对于这道题,我们从1-n进行枚举,假设第 i i i个人为裁判
我们不进行与他相关的任何操作,只进行那些与他无关的操作
如果这样仍然会推出矛盾,那么则证明裁判不是他,并且裁判至少在推出矛盾时仍然出现过
对于推出矛盾的这个点,可以参照其他例题,用并查集扩展域去维护一下即可
对于每个人都进行过这样的操作后,我们就能找出几个人可能为裁判
如果无人可以当裁判,那么就输出Impossible
如果有超过一个人可能为裁判,输出Can not determine
如果只有一个人可能为裁判,那我们就输出这个人的编号以及在第几轮发现的
编号我们可以在求出他为裁判时直接用一个变量记录下来
而他在第几轮被发现,则为每一次推出矛盾时的轮数中的最大值

code
#include
using namespace std;
int n,m;
const int maxn=500+10;
const int maxm=2000+10;
struct node
{
	int x,y;
	char op;
}e[maxm];
int line[maxm],fa[maxn*3];
int find(int x)
{
	if(x==fa[x]) return x;
	else return fa[x]=find(fa[x]);
}
bool check(int x,int y,int op) 
{
    if(op=='>') 
	{
        if((find(x)==find(y))||(find(x)==find(y+n*2))) return 1;
        fa[find(x+n*2)]=find(y);
        fa[find(x)]=find(y+n);
        fa[find(x+n)]=find(y+n*2);
    }
    if(op == '<') 
	{
        if((find(x)==find(y))||(find(x)==find(y+n))) return 1;
        fa[find(x+n)]=find(y);
        fa[find(x)]=find(y+n*2);
        fa[find(x+n*2)]=find(y+n);
    }
    if(op=='=') 
	{
        if((find(x)==find(y+n))||(find(x+n)==find(y))) return 1;
        fa[find(x)]=find(y);
        fa[find(x+n)]=find(y+n);
        fa[find(x+n*2)]=find(y+n*2);
    }
    return 0;
}
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		for(int i=0;i<m;i++) scanf("%d%c%d",&e[i].x,&e[i].op,&e[i].y);
		memset(line,0,sizeof(line));
		int cnt=0,id=0;
		for(int i=0;i<n;i++)
		{
			bool fail=0;
			for(int j=0;j<n*3;j++) fa[j]=j;
			for(int j=0;j<m;j++)
			{
				if(e[j].x!=i&&e[j].y!=i&&check(e[j].x,e[j].y,e[j].op))
				{
					fail=1;
					if(j>line[i]) line[i]=j+1;
					break;
				}
			}
			if(!fail)
			{
				id=i;
				cnt++;
			}
		}
		if(!cnt) puts("Impossible");
		else if(cnt==1)
		{
			int ans=0;
			for(int i=0;i<n;i++) if(line[i]>ans) ans=line[i];
			printf("Player %d can be determined to be the judge after %d lines\n",id,ans);
		}
		else puts("Can not determine");
	}
	return 0;
}

你可能感兴趣的:(算法竞赛进阶指南,c++)