uvalive 5088 hdu3066(树形dp)

8 篇文章 0 订阅

题意:给出一棵n个结点的树,两个人一起走,轮流决策 Alice目的是使最后距离最小 Bob相反
问最终走的距离能否满足区间[L,R]
(需要走到最后不能走,所以Alice不能不选就结束了)
如果没有[L,R],直解dfs,Bob的话选最大儿子走,Alice选最小儿子走
现在多了[L,R],选的时候,就需要判断满足总距离(是总距离!!即答案)满足[L,R]然后再选最大/小
在结点u判断选择是否满足条件时,需要多记录一个dist[u]表示从根0到u的距离
if(dist[u] + dp[v] + w <= R && dist[u] + dp[v] + w >= L)
才更新答案

启示:知道某个节点,就知道了根0到它的距离以及轮到谁决策
这是很有用的性质,最终答案就是 dist[u]+dp[v]+w
转:http://www.cppblog.com/Yuan/archive/2010/10/03/128074.html?opt=admin

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define max(a,b) (a)>(b)?(a):(b)
#define min(a,b) (a)<(b)?(a):(b)
#define clr(x) memset(x,0,sizeof(x))
#define maxn 500005
struct node
{
    int v,next,w;
}edge[10000000];
int tot;
int head[maxn];
int n,L,R;
int dp[maxn];
int d[maxn];
void add(int a,int b,int c)
{
    edge[tot].v=b;
    edge[tot].w=c;
    edge[tot].next=head[a];
    head[a]=tot++;
}

void dfs(int x,int p)
{
    if(d[x]>R)
    {
        dp[x]=0;
        return ;
    }
    int flag=1;
    dp[x]=p?-1:INF;
    for(int i=head[x];~i;i=edge[i].next)
    { //对每个能到这里的点的路径进行dp的更新,因为每次到这个结点的父子结点不一定一样,
        //那么从叶子确定到不同的k也不一样
        int k=edge[i].v;//dp[k]为从叶子结点到当前结点的长度。
        d[k]=d[x]+edge[i].w;//d[k]初始化为0到k的长度
        dfs(k,!p);//往下搜索,往上回溯
        int tmp=d[k]+dp[k];//计算整个路径的长度
        if(tmp>=L&&tmp<=R)
        {
            if(p)
                dp[x]=max(dp[x],dp[k]+edge[i].w);
            else
                dp[x]=min(dp[x],dp[k]+edge[i].w);
        }
    }
    if(flag)
    {
        dp[x]=0;
    }
}


int main()
{
    int i;
    while(scanf("%d%d%d",&n,&L,&R)!=EOF)
    {
        tot=1;
        memset(head,-1,sizeof(head));
        for(int i=1;i<n;i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
        }
        memset(d,0,sizeof(d));
        dfs(0,1);
        if(dp[0]>=L&&dp[0]<=R)
            printf("%d\n",dp[0] );
        else printf("Oh, my god!\n");
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值