題目連結:HDU 3590【PP and QQ】
思路
樹上刪邊問題,套個反尼姆博弈。
反尼姆博弈是取走最後一個石子的人輸掉遊戲,所以需要特判一些特殊情況。
1. 有堆的石子個數都是1,所以堆數為奇數時,先手必敗,否則先手必勝
2. 所有堆中存在石子數為非1的堆時,若所有堆的異或和為0則,先手必敗,否則先手必勝。
克朗原理:對於樹上的某一個點,它的分支可以轉換為這個點為根的一根竹子,這個竹子的長度就是它各個分支的邊的數量的異或和,異或和為0時,先手必勝,異或和為非0時,後手必勝。
程式碼
/*
n棵樹的樹上刪邊
*/
int sg[N], n, flag, t;
vector<int> edge[N];
void init() {
memset(sg, 0, sizeof sg);
for (int i = 0; i <= n; i++) {
edge[i].clear();
}
}
void dfsSG(int x, int fa) {
sg[x] = 0;
for (auto i : edge[x]) {
if (i == fa)
continue;
dfsSG(i, x);
sg[x] ^= (sg[i] + 1);
}
}
void solve() {
int res = 0;
flag = 0;
while (t--) {
n = read();
init();
for (int i = 1; i < n; i++) {
int u = read(), v = read();
edge[u].push_back(v);
edge[v].push_back(u);
}
dfsSG(1, 0);
if (sg[1] > 1)
flag = 1;
res ^= sg[1];
}
if ((res == 0 && flag == 0) || (res && flag)) {
cout << "PP" << endl;
} else {
cout << "QQ" << endl;
}
}
int main() {
while (~scanf("%d", &t)) {
solve();
}
return 0;
}