HDU 3660 树形DP

原题地址

题意

Alice与Bob在一棵树的树根一同出游,两人从Bob开始轮换选择道路一直走到树叶,Alice会尽可能使走过的总长最小,而Bob相反。不过他们都不能让总长落到[l, r]之外


现在给出这棵树和l,r,要求我们判断最终走过的总长落到[l, r]内,如果能,则输出这个总长,否则输出Oh, my god!

思路

  • 由于两人都是最理性地考虑自己的选择,并且在某点由哪个人选择道路是已知的,所以可以使用DP

  • 在某个节点,从子节点的预期长度中选出使最终路径长度落在[l, r]内并且最大(小)的一个,加上对应的这条道路的长度,就是本节点到叶子节点的预期长度。

  • 在hdu上交的时候要注意优化,但是似乎这题数据太强了,即使通过也是和时限差了50ms,可以去做相同的uva-1484,数据要友好很多。

AC代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int n;
long long l, r;
int fir[500005], nex[500005], vv[500005];
int ff[500005], ww[500005];

void dfs(int o, int d, int v)
{
	if (fir[o] == -1)
	{
		if (v > r || v < l)
		{
			ff[o] = -1;
			return;
		}
		ff[o] = 0;
		return;
	}
	ff[o] = d % 2 ? -1 : 99999999;
	for (register int i = fir[o]; i != -1; i = nex[i])
	{
		dfs(vv[i], d + 1, v + ww[i]);
		if (ff[vv[i]] == -1 || ff[vv[i]] == 99999999)
		{
			continue;
		}
		int acc = ff[vv[i]] + v + ww[i];
		if (acc > r || acc < l)
		{
			continue;
		}
		if (d % 2)
		{
			ff[o] = max(ff[o], ww[i] + ff[vv[i]]);
		}
		else
		{
			ff[o] = min(ff[o], ww[i] + ff[vv[i]]);
		}
	}
	return;
}

int main()
{
	while (scanf("%d%lld%lld", &n, &l, &r) != EOF)
	{
		memset(fir, -1, sizeof(int) * (n + 2));
		for (register int i = 1; i < n; ++i)
		{
			int u;
			scanf("%d%d%d", &u, &vv[i], &ww[i]);
			nex[i] = fir[u];
			fir[u] = i;
		}
		dfs(0, 1, 0);
		if (ff[0] != -1 && ff[0] != 99999999)
		{
			printf("%d\n", ff[0]);
		}
		else
		{
			printf("Oh, my god!\n");
		}
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值