1. 程式人生 > >hihocoder1545 : 小Hi和小Ho的對弈遊戲(樹上博弈&nim博弈)

hihocoder1545 : 小Hi和小Ho的對弈遊戲(樹上博弈&nim博弈)

描述

小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行,每行包含兩個整數 xy,代表 xy 的父節點。保證輸入是一棵樹,節點編號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; }