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

https://ac.nowcoder.com/acm/contest/3005/F
现有一个 n 个点,n-1条边组成的树,其中 1 号点为根节点。

牛牛和牛妹在树上玩游戏,他们在游戏开始时分别在树上两个不同的节点上。

在游戏的每一轮,牛牛先走一步,而后牛妹走一步。他们只能走到没有人的空节点上。如果谁移动不了,就输掉了游戏。现在牛牛和牛妹决定随机选择他们分别的起点,于是他们想知道,有多少种游戏开始的方式,使得牛牛存在一种一定获胜的最优策略。

两种开始方式相同,当且仅当在两种开始方式中牛牛,牛妹的开始位置是分别相同的,否则开始方式就被视作不同的。

思路 

首先考虑输的情况,因为是一棵树 ,而且只能走没走过的点,输的时候就是接下来唯一能走的点被走过了或者牛妹在那里,因为两个人都会做出最优的策略,所以只有对方才会卡到自己的下一步的位置,也就是说如果走了一段时间他们的距离是1了,并且该牛牛走了, 牛牛就输了,向外延伸可以发现,他们两个是轮流走的,每次都是走1,所以距离每次变化+1或者-1,两个人都走过后距离+0或者+2或者-2,总的来说都是偶数,也就是说他们的距离变化不影响距离的奇偶性,如果一开始奇数,变化一段时间后肯定还是奇数,最后就会变成1,牛牛输了,同理,一开始偶数那么随着一直变化,最后会变成2,然后牛牛走完变成1,牛牛就赢了,只需要计算一下距离为偶数的点对个数即可。通过dfs计算每个点的深度,统计深度为奇数和偶数的点,奇数+奇数=偶数,偶数+偶数=偶数,所以最后结果就是(奇数点个数)*(奇数点个数-1)+(偶数点个数)*(偶数点个数-1)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
const int N = 1e6 + 10;
int root[N];
int f[N];
int head[N], nex[N], to[N], cnt;
void add(int a, int b) {
	++cnt;
	to[cnt] = b;
	nex[cnt] = head[a];
	head[a] = cnt;
}
void dfs(int now) {
	for (int i = head[now]; i; i = nex[i]) {
		int y = to[i];
		f[y] = f[now] + 1;
		dfs(y);
	}
}
int main()
{
	ios::sync_with_stdio(0);
	cin >> n;
	memset(head, 0, sizeof head);
	memset(nex, 0, sizeof nex);
	cnt = 0;
	for (int i = 2; i <= n; i++) {
		cin >> root[i];
		add(root[i], i);
	}
	f[1] = 0;
	dfs(1);
	ll odd, even;
	odd = 0;
	even = 0;
	for (int i = 1; i <= n; i++) {
		if (f[i] & 1)odd++;
		else even++;
	}
	ll res = odd * (odd - 1) + even * (even - 1);
	printf("%lld\n", res);
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值