并查集应用。
这道题目和 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; }