HDU 3590 PP and QQ

薛定谔的AC發表於2024-08-16

題目連結: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;
}