HDU 6741 树上删叶子节点博弈
假设现在有一颗树A
我们在他非叶子节点上加一个点变成树B 则此时树B必为先手必胜
假设A为先手必胜 则先手直接把加入的点一同删去
假设A为先手必败 则先手可以只删加入的点 与后手位置互换 把必败态留给后手
所以只要有一个非叶子节点连着一个叶子节点(叶子节点父亲的度数>2) 此时的树为先手必胜
排除掉这种必胜情况 剩下的就是每个叶子节点的父亲度数都为2的情况
则我们可以计算每个叶子到他第一个度数>2的祖先的长度 如果所有这些长度都为偶数的话 那么是后手必胜
策略是这样的: 我们定义叶子节点到他第一个度数>2的祖先路上的经过的节点和边为'链'
假设先手这次拿了集合为S的链上的叶子节点 那么后手也拿集合为S的链上的叶子节点 这样每条链的长度还是偶数 直到有一条链他只剩一个节点直接转换为上面的必胜情况
如果有一条链是奇数的话 就是先手必胜 因为先手直接把所有链拿成偶数就可以和后手位置互换 把必败态留给后手
#include<bits/stdc++.h> using namespace std; int fa[1000005]; vector<int> G[1000005], yezi; int du[1000005], Size[1000005]; int main() { int T; scanf("%d", &T) ; while (T--) { int n, x; scanf("%d", &n); yezi.clear(); for (int i = 1; i <= n; i++) { Size[i] = du[i] = 0; G[i].clear(); } for (int i = 2; i <= n; i++) { scanf("%d", &x); fa[i] = x; du[x]++; Size[x]++; } for (int i = 1; i <= n; i++) { if (du[i] == 0) { yezi.push_back(i); } } bool flag = 0; for (int v : yezi) { int father = fa[v]; if (Size[father] >= 2) { flag = 1; break; } int cnt = 1; while (Size[fa[v]] == 1) { cnt++; v = fa[v]; } if (cnt & 1) { flag = 1; break; } } if (flag) { printf("Takeru\n"); } else { printf("Meiya\n"); } } return 0; }