2020牛客寒假算法基础集训营4 F 树上博弈

题目描述

现有一个 n 个点,n-1条边组成的树,其中 1 号点为根节点。
牛牛和牛妹在树上玩游戏,他们在游戏开始时分别在树上两个不同的节点上。
在游戏的每一轮,牛牛先走一步,而后牛妹走一步。他们只能走到没有人的空节点上。如果谁移动不了,就输掉了游戏。现在牛牛和牛妹决定随机选择他们分别的起点,于是他们想知道,有多少种游戏开始的方式,使得牛牛存在一种一定获胜的最优策略。
两种开始方式相同,当且仅当在两种开始方式中牛牛,牛妹的开始位置是分别相同的,否则开始方式就被视作不同的。

输入描述:

第一行输入为一个整数 n,代表树的点数。
第二行n-1个整数$ p_2,p_3,...,p_n $ ,分别代表2,3,...,n号点的父节点编号。
$ n\leq 10^6,1 \leq p_i< i. $

输出描述:

一行一个整数,代表答案。

输入

3
1 2

输出

2

说明

当且仅当牛牛在1号点,牛妹在3号点,或者牛牛在3号点,牛妹在1号点时,牛牛才获胜。

传送门:

https://ac.nowcoder.com/acm/contest/3005/F
 
     

思路:

首先自己输掉的唯一方法是自己在叶节点,而另一个人在该叶节点的父节点上。

此时两人的距离D为奇数。

两人的距离D为奇数时,A先走使得两个人的距离D减小(也就是往根节点走)。

B也可以采取同样的策略使得两人的距离D减小,最后会到两人的距离为1,该A走。

此时A只能往叶节点走,B只要跟着A往叶节点走就能获胜。

偶数的情况同理。

所以该题只要计算一下每个结点的深度即可。

代码:

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 const int N = 1e6 + 10;
 6 
 7 struct node
 8 {
 9     int nxt;
10     int to;
11 };
12 
13 node t[N];
14 int head[N];
15 bool vis[N];
16 int d[N];
17 
18 int tot;
19 void addedges(int u, int v)
20 {
21     t[++tot].to = v;
22     t[tot].nxt = head[u];
23     head[u] = tot;
24 }
25 void dfs(int x)
26 {
27     vis[x] = true;
28 
29     for(int i = head[x]; i; i = t[i].nxt)
30     {
31         int y = t[i].to;
32         if(!vis[y])
33         {
34             d[y] = d[x] + 1;
35             dfs(y);
36         }
37     }
38 }
39 int main()
40 
41 {
42     int n;
43     scanf("%d", &n);
44     for(int i = 2; i <= n; i++)
45     {
46         int x;
47         scanf("%d", &x);
48         addedges(x, i);
49     }
50     dfs(1);
51 
52     long long a = 0;
53     long long b = 0;
54     for(int i = 1; i <= n; i++)
55     {
56         if(d[i] % 2)
57             a++;
58         else
59             b++;
60     }
61     printf("%lld\n", (a - 1)*a + (b - 1)*b );
62 }


 

猜你喜欢

转载自www.cnblogs.com/yyaoling/p/12298257.html