版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sugarbliss/article/details/89526049
题目链接:http://poj.org/problem?id=2912
题意:n个人进行m轮剪刀石头布游戏,'='表示x, y平局,'>'表示x赢y,'<'表示x输y,但是我们不知道x, y的手势是什么; 其中有一个人是裁判,它可以出任意手势,其余人手势相同的分一组,共分为三组,可以存在空组,也就是说除了裁判外,其余人每一次出的手势都相同,问能不能确定裁判是几号,如果能,输出最少在第几轮可以确定。
思路:这一题的关系和食物链是一样的,定义0表示平局,1表示x赢y,2表示y赢x。我们枚举裁判,如果我们得到的可能为裁判的节点唯一,那么它就是裁判,如果得到可能为裁判的节点有多个,那么就不能确定裁判,如果可能为裁判的节点一个都没有,就是Impassible。枚举每个编号为裁判,一但在某一行输入中出现矛盾,我们就确定枚举的这个编号不是裁判,那么n-1个出现矛盾的枚举中出现矛盾最晚的那个行数即为我们能确定裁判所需的最少行数(因为我们要排除n-1个编号才能确定裁判的编号)。
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int N = 1e5 + 7;
int f[N], w[N], n, m, flag;
int a[N], b[N]; char ch[N];
void init()
{
for(int i = 0; i <= n; i++)
f[i] = i, w[i] = 0;
}
int findd(int x)
{
if(x == f[x]) return x;
int t = f[x];
f[x] = findd(f[x]);
w[x] = (w[x] + w[t] + 3) % 3;
return f[x];
}
int unint(int x, int y, int d)
{
int tx = findd(x), ty = findd(y);
if(tx != ty)
{
f[tx] = ty;
w[tx] = (-w[x] + w[y] + d + 3) % 3;
}
else
{
if((w[x] - w[y] + 3) % 3 != d)
return 1;
}
return 0;
}
int main()
{
while(~scanf("%d%d",&n, &m))
{
init(); int d;
for(int i = 1; i <= m; i++)
scanf("%d%c%d", &a[i], &ch[i], &b[i]);
int id = 0, ans = 0, cnt = 0, flag;
for(int i = 0; i < n; i++)
{
init(); flag = 0;
for(int j = 1; j <= m; j++)
{
if(i == a[j] || i == b[j]) continue;
if(ch[j] == '=') d = 0;
if(ch[j] == '>') d = 1;
if(ch[j] == '<') d = 2;
if(unint(a[j], b[j], d))
{
ans = max(ans, j), flag = 1;
break;
}
}
if(!flag) id = i, cnt++;
}
if(cnt == 0) puts("Impossible");
else if(cnt > 1) puts("Can not determine");
else printf("Player %d can be determined to be the judge after %d lines\n", id, ans);
}
return 0;
}
/*
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
*/