【题目链接】
http://poj.org/problem?id=2912
题目意思
一群人玩石头,剪刀,布;把这群人分成3组,分别只能出石头,剪刀,布。但是其中有个是裁判可以任意出。现在给你m组两两对决的结果,问是否能找到裁判,如果能输出裁判序号和在第几个对决结果出来时找到的。不能输出对应字符串。
解题思路
这题是在poj1182食物链上加个裁判形成的。所以只要遍历去除某一点有关的边。如果形成的集合不冲突,那么这个点就有可能是裁判。当可能个数为1时就能找到裁判。同时在冲突点中找到需要步数最多才冲突的那个点的步数。如果不等于1输出对应字符串。
代码部分
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <queue>
#include <string>
#include <map>
using namespace std;
#define LL long long
#define inf 0x3f3f3f3
const int N = 1005;
int pre[N]; ///记录集合序号
int val[N]; ///权值
int n,m,ans;
bool fa;
int Max; ///最大错误步数
struct node
{
int x,y,k;
}a[N*2];
void init() ///初始化
{
for (int i = 0; i < n; i++)
{
pre[i] = i;
val[i] = 0;
}
ans = 0 ;
fa = true;
}
int fin(int x)
{
int k = pre[x];
if (x != pre[x])
{
pre[x] = fin(pre[x]);
val[x] = (val[x]+val[k])%3;
}
return pre[x];
}
void join(int x,int y,int k)
{
int fx = fin(x);
int fy = fin(y);
if (fy == fx && (val[x]+k)%3 != val[y]) ///不满足
fa = false;
else
{
pre[fy] = fx;
val[fy] = (val[x]-val[y]+k+3)%3; ///权值更新
}
}
int main()
{
while (scanf("%d %d",&n,&m)!=EOF)
{
int x,y,k,t=0;
Max = 0;
char c;
for (int i = 0; i < m; i++)
{
scanf("%d%c%d",&a[i].x,&c,&a[i].y);
if (c == '=')
a[i].k = 0;
else if (c == '>')
a[i].k = 1;
else a[i].k = 2;
}
for (int i = 0; i < n; i++) ///遍历每个人
{
init();
for (int j = 0; j < m;j++)
{
if (fa) ///计算错误在第几步
ans++;
if (a[j].x == i || a[j].y == i) ///排除带i的边
continue;
join(a[j].x,a[j].y,a[j].k);
}
if (fa)
{
t++; ///判断可以为裁判的个数
k = i;
}
else
{
if (ans > Max)
Max = ans;
}
}
if (t > 1)
printf("Can not determine\n");
else if (t == 0)
printf("Impossible\n");
else printf("Player %d can be determined to be the judge after %d lines\n",k,Max);
}
return 0;
}