HDU6741 题目描述: 每次可以拿任意个数的叶子节点。 谁取走根节点谁赢。 首先一个比较明显的结论就是如果一个叶子节点有兄弟节点的话一定是先手必胜的。(这个节点不影响你取其他节点,且如果其他节点都不能取,你可以取走这个节点)。 同时这个也意味着如果参加游戏的某一方通过自己的操作给另外一方填了一个叶子结点,且该叶子节点有兄弟节点,那么就相当于将胜态给了对方。 根据这个结论,继续拓展一下。 我们建两个数组。 fa[i]统计i的儿子的数量。 pre[i]统计i的父亲的节点号 有了这两个我们就可以解决这个问题了。 首先当该数所有的fa的值都为1,即所有的点连成一条链。 那么显而易见链的长度的奇偶性决定了谁赢。 下面我们讨论至少存在一个点他的fa值大于等于2。 首先可以明确的是fa[i]等于0的节点i是叶子节点,那么可以通过pre[i]向上遍历,找到它的祖先节点,如果这个祖先节点的fa值大于等于2(我们排除一条链之后,是存在这样的点的),根据上面的讨论,我们可以知道,如果该链长度为2时就不能再取了,(取完相当于新添加有兄弟节点的一个叶子节点)。再推广一下不难发现,如果我们把所有的叶子节点都遍历到其第一个fa值大于等于2的祖先节点,如果有一条,长度为奇数的链,那么先手必胜。(偶数长度的链都不能动,而长度为奇数的所有串可以一次操作将其变为偶数长度的链)。 代码比较简单。
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+500; int fa[maxn],pre[maxn]; int main(){ int t; scanf("%d",&t); for(int i=0;i<t;i++){ int n; scanf("%d",&n); memset(fa,0,sizeof(int)*(n+200)); for(int i=2;i<=n;i++){ int a; scanf("%d",&a); fa[a]++; pre[i]=a; } bool flag=false; bool flagfa=true; for(int i=2;i<=n;i++){ if(fa[i]>=2) flagfa=false; if(fa[i]==0&&fa[pre[i]]>=2){ flag=true; break; } } if(flag) printf("Takeru\n"); else { if(fa[1]>=2) flagfa=false; if(flagfa){ if(n%2==1) printf("Takeru\n"); else printf("Meiya\n"); } else{ for(int i=2;i<=n;i++){ int len=0; if(fa[i]==0){ for(int j=i;j>=1;j=pre[j]){ len++; if(fa[j]>=2) break; } if((len-3)%2==1){ flag=true; break; } } } if(flag) printf("Takeru\n"); else printf("Meiya\n"); } } } }