并查集应用。
这道题目和 POJ 1182 食物链 非常类似。
枚举所有judge,不处理出现当前judge的round,然后利用食物链的解法判断冲突。就可以找出来最终的judge。
还有一步就是找到judge之后,要得到确定此judge的round数:这个round数就是在枚举的时候,其他人出错的round数的最大值——因为,到这个最大round数时,其他人都被排除,剩下的就是真正的judge
#include <cstdio>
#include <cstring>
const int MAXN = 505;
const int MAXM = 2004;
int set[MAXN], a[MAXN];
struct node {
int u, v;
char ch;
} p[MAXM];
/*
a[x] = 0 =
a[x] = 1 <
a[x] = 2 >
*/
int f1[3][3] = {{0, 1, 2}, {2, 0, 1}, {1, 2, 0}};
int f2[3][3] = {{1, 2, 0}, {0, 1, 2}, {2, 0, 1}};
int f3[3][3] = {{2, 0, 1}, {1, 2, 0}, {0, 1, 2}};
int n, m;
int Find_set(int x) {
if (set[x] == x) return x;
int t = Find_set(set[x]);
a[x] = (a[x] + a[set[x]]) % 3;
return set[x] = t;
}
void Union(int x, int y, char ch) {
int fx = Find_set(x);
int fy = Find_set(y);
set[fx] = fy;
if (ch == '=') a[fx] = f1[a[x]][a[y]];
else if (ch == '<') a[fx] = f2[a[x]][a[y]];
else a[fx] = f3[a[x]][a[y]];
}
void solve() {
int x, y, fx, fy;
int err[MAXN];
memset(err, 0, sizeof(err));
for (int j=0; j<n; j++) { //枚举judge
for (int i=0; i<n; i++)
set[i] = i, a[i] = 0;
for (int i=0; i<m; i++) {
x = p[i].u, y = p[i].v;
if (x == j || y == j) continue;
fx = Find_set(x);
fy = Find_set(y);
if (fx == fy) {
if (p[i].ch == '=' && a[x]!=a[y]) {
err[j] = i+1; break;
}
if (p[i].ch == '<' && (a[x]+2)%3 != a[y]) {
err[j] = i+1; break;
}
if (p[i].ch == '>' && (a[x]+1)%3 != a[y]) {
err[j] = i+1; break;
}
} else Union(x, y, p[i].ch);
}
}
int cnt = 0, k, ans = 0;
for (int i=0; i<n; i++) {
if (err[i] == 0) cnt++, k = i;
if (err[i] > ans) ans = err[i];
}
if (cnt == 0) printf("Impossible\n");
else if (cnt == 1)
printf("Player %d can be determined to be the judge after %d lines\n", k, ans);
else printf("Can not determine\n");
}
int main() {
while (scanf("%d %d", &n, &m) == 2) {
for (int i=0; i<m; i++)
scanf(" %d%c%d", &p[i].u, &p[i].ch, &p[i].v);
solve();
}
return 0;
}