描述
小Hi和小Ho经常一起结对编程,他们通过各种对弈游戏决定谁担任Driver谁担任Observer。
今天他们的对弈是在一棵有根树 T 上进行的。小Hi和小Ho轮流进行删除操作,其中小Hi先手。
游戏的规则是:每次删除,小Hi或小Ho都可以选择一个非根节点,将以该节点为根的子树从 T 中删除。如果删除之后 T 只剩下一个根节点,则该次操作者胜利。
机智的小Ho认为规则对自己不利,于是他提出了一个补充规则:在小Hi第一次删除之前,小Ho可以选择是否删除根节点。如果他选择删除根节点,则原本的有根树 T 会分裂成一个森林。之后每次删除,小Hi或小Ho都可以选择一个非根节点(不是森林中任何一棵树的根),将以该节点为根的子树删除。如果删除之后森林中只剩下根节点,则该次操作者胜利。
小Hi和小Ho都是睿智的玩家,他们总是会选择最优的方案以获得胜利。
给定初始的有根树T,输出两个布尔值,分别代表小Ho在不删除和删除根节点时,先手的小Hi是否有必胜策略。0代表没有,1代表有。
输入
第一行包含一个整数 Q,代表测试数据的组数。1 ≤ Q ≤ 10
对于每组数据,第一行包含一个正整数 n,代表树T的节点个数。1 ≤ n ≤ 100000
接下来n-1行,每行包含两个整数 x 和 y,代表 x 是 y 的父节点。保证输入是一棵树,节点编号1-n。
输出
输出一个长度为2Q的01串,代表答案。
- 样例输入
-
2 5 2 5 5 4 2 3 1 2 7 4 7 2 6 1 5 3 4 1 3 1 2
- 样例输出
-
1101
思路:green博弈(树删边游戏):规则为每次选择一条边删去,被删去的子树不能再被选,没有可删的一方输掉比赛。
这种题还是要用SG函数来做,此题是最基本的green博弈,我们考虑只有一条边,那么这个边的sg函数就是长度(看成一堆石子);考虑根上有两条链,那么其sg函数就是两个长度的异或(看成两堆石子)...可以推出每个节点的sg函数=所有子节点的sg+1的异或和。
#include<bits/stdc++.h> #define rep(i,o,l) for(int i=o;i<=l;i++) using namespace std; const int maxn=200010; int Laxt[maxn],Next[maxn],To[maxn],cnt; int sg[maxn],fcy,ind[maxn],rt; void add(int u,int v) { Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; } void dfs(int u,int f) { sg[u]=0; for(int i=Laxt[u];i;i=Next[i]) if(To[i]!=f) dfs(To[i],u); sg[f]^=(sg[u]+1); if(f==rt) fcy^=sg[u]; } int main() { int T,N,u,v; scanf("%d",&T); while(T--){ scanf("%d",&N); cnt=0; fcy=0; rep(i,1,N) ind[i]=0,Laxt[i]=0; rep(i,1,N-1) { scanf("%d%d",&u,&v); add(u,v); ind[v]++; } rep(i,1,N) if(!ind[i]) rt=i; dfs(rt,0); putchar(sg[rt]?‘1‘:‘0‘); putchar(fcy?‘1‘:‘0‘); } return 0; }
原文地址:https://www.cnblogs.com/hua-dong/p/10173141.html