有一个棋子放在一颗有根树的根上。你和算卦先生轮流把这个棋子向所在点的其中一个儿子移动(只能移动到儿子)。不能再移动就算失败(即棋子所在节点没有儿子)。
算卦先生来问你,如果你先手,你是否有必胜策略
分析:用DFS,从根到尾一点点来,因为会沿着一条路径走到黑,每个点只会被访问到一次,大致是O(N)级的复杂度;
用pre来标记父节点免得上下来回走,如果有节点可走,就继续往下走,没节点可走时返回f。
或者是该节点的所有儿子节点都是叶子(这种情况下它们都会返回TRUE),也会返回f
一层层往上推进,在最上面一层,只要有一个节点是必赢节点,选择这个节点,即可赢(因为只要所有儿子节点都是True,返回值才会为负)
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int inf=1<<30; 4 typedef long long ll; 5 const double pi=acos(-1); 6 const int mod=1e9+7; 7 const int maxn=1e4+7; 8 vector<int> v[maxn]; 9 //dfs函数每层返回的是在这一层下棋的人是输还是赢 10 bool dfs(int s,int pre){//pre函数记录它是从哪层来的,免得父到子,子又到父 11 for(int i=0;i<v[s].size();i++){ 12 int a=v[s][i]; 13 if(a==pre) continue; 14 if(!dfs(a,s)) return true;//下一层走不了了,那这一层就是最后一层,在这一层执棋的人就赢 15 } 16 return false;//所有边都遍历完了仍没找到可赢的情况,说明这一层无法走,返回FALSE 17 } 18 int main(){ 19 int T;scanf("%d",&T); 20 while(T--){ 21 int n,r;scanf("%d%d",&n,&r); 22 for(int i=1;i<=n;i++) v[i].clear(); 23 for(int i=1;i<n;i++){ 24 int x,y;scanf("%d%d",&x,&y); 25 v[x].push_back(y); 26 v[y].push_back(x); 27 } 28 if(dfs(r,-1)) cout<<"Gen "; 29 else cout<<"Dui "; 30 } 31 return 0; 32 }