牛客小白月赛2 F 黑黑白白

题目链接

有一个棋子放在一颗有根树的根上。你和算卦先生轮流把这个棋子向所在点的其中一个儿子移动(只能移动到儿子)。不能再移动就算失败(即棋子所在节点没有儿子)。
算卦先生来问你,如果你先手,你是否有必胜策略

分析:用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\n";
29         else cout<<"Dui\n";
30     }
31     return 0;
32 }

猜你喜欢

转载自www.cnblogs.com/qingjiuling/p/10424516.html