HDU 3590 PP and QQ

题目链接: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;
}
posted @ 2024-08-16 21:00  薛定谔的AC  阅读(1)  评论(0编辑  收藏  举报