HDU 4276

HDU 4276 The Ghost Blows Light

题目描述:

有一棵树,N~100,有时间T~500,起点是编号1,重点是给出的N,每个点有若干个宝,要求在时间内走到N出去,并且尽量拿到多的宝藏,输出最多宝藏数.

题解:

有个小技巧可以简化思维.一定要走的路先走一遍,并且不会反复走.这样先搞出,然后把路上的花费消除掉.之后就是正常的树形dp,加一维表示用了多少时间.画一个图就发现剩下的是树形依赖背包,想要用多少,画多少的时间.

重点:

简化思维.定状态时因为有一定要走的地方,所以不好弄,一定走的就先走,然后再贪心的定新的状态,一定要走的走.这样之后简化为一个树形依赖背包.而不是最初的定状态走到哪里.

代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(int i = a;i < b;i++)
#define REP_D(i, a, b) for(int i = a;i <= b;i++)

typedef long long ll;

using namespace std;

const int maxn = 500 + 10;
int flag[maxn], dp[maxn][maxn], val[maxn], a, b, n, tot;
struct info
{
    int to, t;
};
vector<info> G[maxn];
void dfs_flag(int u, int fa)//代码很简单,这是标记必走的路.
{
    flag[u] = 0;
    int tag = 0;
    REP(i, 0, G[u].size())
    {
        int v = G[u][i].to;
        if(v!=fa)
        {
            dfs_flag(v, u);
            if(flag[v]!=0)
            {
                tag = 1;
            }
        }
    }
    if(u == b)
    {
        tag = 1;
    }
    flag[u] = tag;
}
void dfs(int u, int fa)//树形依赖背包,因为要根据fa到u的长度来定代价,所以再传下去的时候就进行减掉.其实这样写有点复杂了.因该分开写,先走一遍一定要走的路,然后把总时间减掉,之后再正常的dp就好了,因为一切的都是要回到原点的dp.
{
    if(flag[u]==0 || u == b)
    {
        REP(i, 0, G[u].size())
        {
            int v = G[u][i].to, t = G[u][i].t;
            if(v!=fa)
            {
                for(int j = t*2; j <= tot; j++)
                {
                    if(dp[u][j-t*2]!=-1)
                        dp[v][j] = dp[u][j-t*2]+val[v];
                    else
                        dp[v][j] = -1;
                }
                for(int j = 0; j < t*2; j++)
                {
                    dp[v][j] = -1;
                }
                dfs(v, u);
                for(int j = 0; j <= tot; j++)
                {
                    dp[u][j] = max(dp[u][j], dp[v][j]);
                }
            }
        }
    }
    else
    {
        REP(i, 0, G[u].size())
        {
            int v = G[u][i].to, t = G[u][i].t;
            if(v!=fa&&flag[v]==1)
            {
                for(int j = t; j <= tot; j++)
                {
                    if(dp[u][j-t]!=-1)
                        dp[v][j] = dp[u][j-t]+val[v];
                    else
                        dp[v][j] = -1;
                }
                for(int j = 0; j < t; j++)
                {
                    dp[v][j] = -1;
                }
                dfs(v, u);
                for(int j = 0;j <= tot;j++)
                    dp[u][j] = dp[v][j];
            }
            else if(v!=fa&&flag[v]==0)
            {
                for(int j = t*2; j <= tot; j++)
                {
                    if(dp[u][j-t*2]!=-1)
                        dp[v][j] = dp[u][j-t*2]+val[v];
                    else
                        dp[v][j] = -1;
                }
                for(int j = 0; j < t*2; j++)
                {
                    dp[v][j] = -1;
                }
                dfs(v, u);
                for(int j = 0; j <= tot; j++)
                {
                    dp[u][j] = max(dp[u][j], dp[v][j]);
                }
            }
        }
    }
}
void solve()
{
    dfs_flag(a, 0);
    for(int j = 0; j <= tot; j++)
    {
        dp[a][j] = - 1;
    }
    dp[a][0] = val[a];
    dfs(a, 0);
    int ans = -1;
    for(int i = 0;i <= tot;i++)
    {
        ans = max(ans, dp[a][i]);
    }
    if(ans == -1)
    {
        printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!\n");
    }
    else
    {
        printf("%d\n", ans);
    }
}

int main()
{
   // freopen("1Ain.txt", "r", stdin);
    //freopen("1Aout.txt", "w", stdout);
    while(scanf("%d%d", &n, &tot) != EOF)
    {
        REP_D(i, 1, n)
        {
            G[i].clear();
        }
        REP_D(i, 1, n - 1)
        {
            int x, y, len;
            scanf("%d%d%d", &x, &y, &len);
            info t;
            t.to = y;
            t.t = len;
            G[x].push_back(t);
            t.to = x;
            G[y].push_back(t);
        }
        a = 1;
        b = n;
        REP_D(i, 1, n)
        {
            scanf("%d", &val[i]);
        }
        solve();
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值