树形DP + 最优值选择
题意:
两个人相约去旅游,有n个地方,其边和点组成一个树,现在要从0节点出发,bob和Alice轮流选择走的方向,Bob先选择,他总是选择大的,Alice总是选择小的,总路程要在一个区间里面,问最优解是多少?
思路:
因为树是固定的,其实每一层的选择也就是也是可以确定的,不确定的是有些路会超过范围,用dp保存即可。
定义: dp[u][0/1] 表示到节点u 的最大值,0代表Bob选择,1代表Alice选择。
- 那只需要遍历每一条路即可,当选择这条路的时候其实值可以确定,所以需要判断一下取最优值,当然dfs中最后的结果一定到达了最后的叶子节点,不满足就输出字符串。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 500005;
const int inf = 0x3f3f3f3f;
int n,l,r;
int dp[maxn][2];
int head[maxn],pos;
struct Node
{
int e,v;
int next;
}edge[maxn];
void init()
{
pos = 0;
memset(head,-1,sizeof(head));
}
void input()
{
for(int i = 0;i < n-1; i++) {
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
edge[pos].e = b;
edge[pos].v = c;
edge[pos].next = head[a];
head[a] = pos++;
}
}
int judge(int x)
{
return (x >= l && x <= r);
}
void dfs(int u,int value)
{
dp[u][0] = 0;
dp[u][1] = (head[u] == -1 ? 0 : inf);
for(int i = head[u];i != -1; i = edge[i].next) {
int to = edge[i].e;
dfs(to,value + edge[i].v);
if(judge(value + edge[i].v + dp[to][1])) {
dp[u][0] = max(dp[u][0],dp[to][1] + edge[i].v);
}
if(judge(value + edge[i].v + dp[to][0])) {
dp[u][1] = min(dp[u][1],dp[to][0] + edge[i].v);
}
}
}
int main(int argc, char const *argv[])
{
//freopen("in.txt","r",stdin);
while(scanf("%d%d%d",&n,&l,&r) != EOF) {
init();
input();
dfs(0,0);
if(dp[0][0] == 0) {
printf("Oh, my god!\n");
}
else
printf("%d\n",dp[0][0]);
}
return 0;
}