题意、思路:
跟poj1182食物链题意题意几乎是一样的,那个题目的意思是a吃b,b吃c,c吃a,而这个是剪子包袱锤,所以说是一样的。只需要把这个题的数据稍微变换一下,【把这道题目的的"a>b"和"a<b"变成那个题的(1 a b),(1 b a)即可】,就不用推新的公式了,那么集合合并和路径压缩的公式还是用原来的就可以了。
不同的是这道题目需要用多次并查集。对于这个题我们的做法是,枚举每个小孩为judge,并记录他为judge时在第几句话出错(即到第几句话能判断该小孩不是judge)。
1. 如果只有1个小孩是judge时全部语句都是正确的,说明该小孩是judge,那么判断的句子数即为其他小孩的出错位置的最大值。如果
2. 如果每个小孩的都不是judge(即都可以找到出错的语句),那么就是impossible。
3. 多于1个小孩是judge时没有找到出错的语句,就是Can not determine。
跟poj1182食物链题意题意几乎是一样的,那个题目的意思是a吃b,b吃c,c吃a,而这个是剪子包袱锤,所以说是一样的。只需要把这个题的数据稍微变换一下,【把这道题目的的"a>b"和"a<b"变成那个题的(1 a b),(1 b a)即可】,就不用推新的公式了,那么集合合并和路径压缩的公式还是用原来的就可以了。
不同的是这道题目需要用多次并查集。对于这个题我们的做法是,枚举每个小孩为judge,并记录他为judge时在第几句话出错(即到第几句话能判断该小孩不是judge)。
1. 如果只有1个小孩是judge时全部语句都是正确的,说明该小孩是judge,那么判断的句子数即为其他小孩的出错位置的最大值。如果
2. 如果每个小孩的都不是judge(即都可以找到出错的语句),那么就是impossible。
3. 多于1个小孩是judge时没有找到出错的语句,就是Can not determine。
代码如下:
const int M = 2005;
const int N = 505;
struct Rec
{
int a, b, o;
}rec[M];
int p[N], flag[N];
int find(int x)
{
int tmp = p[x];
p[x] = (p[x]==x?x:find(p[x]));
flag[x] = (flag[tmp]+flag[x])%3;
return p[x];
}
int main()
{
int n, m, a, b;
char tmp;
while(~scanf("%d%d", &n, &m))
{
for(int i = 0; i < m; ++i)
{
scanf("\n%d%c%d", &a, &tmp, &b);
rec[i].o = (tmp=='='?1:2);
if(tmp=='>')
rec[i].a = a, rec[i].b = b;
else
rec[i].a = b, rec[i].b = a;
}
int ansi, ansm = 0, cnt = 0;
for(int i = 0; i < n; ++i)
{
int isBreak = 0;
memset(flag,0,sizeof(flag));
for(int j = 0; j < n; ++j) p[j] = j;
for(int j = 0; j < m; ++j)
{
if(rec[j].a==i||rec[j].b==i) continue;
int a = rec[j].a;
int b = rec[j].b;
int o = rec[j].o;
int x = find(a);
int y = find(b);
if(x==y && (flag[b]-flag[a]+o)%3!=1)
{
isBreak = j+1;
break;
}
else if(x != y)
{
p[x] = y;
flag[x] = (flag[b]-flag[a]+2+o)%3;
}
}
if(isBreak) ansm = max(ansm,isBreak);
else ansi = i, cnt += 1;
}
if(cnt==0) printf("Impossible\n");
else if(cnt>1) printf("Can not determine\n");
else printf("Player %d can be determined to be the judge after %d lines\n", ansi, ansm);
}
return 0;
}