HDOJ 4276 The Ghost Blows Light(树形DP+背包)

长春网赛倒数第2题

题意:给一颗带权树,树的边权代表通过所需的费用,树中每个节点有一个value,代表财富值,从结点1出发,求在时间T内到达结点n最多能带走的财富。

分析:从1到n有一条必经之路,对这条路上的结点用树形DP求泛型背包,然后对这些点进行分组背包。

复制代码
View Code
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
#define MAX(a,b) ((a)>(b)?(a):(b))
#define N 101
int n,T,e;
int first[N],next[N<<1],v[N<<1],t[N<<1],val[N];
int dp[N][5*N],ans[5*N];
int d[N],p[N];
bool vis[N];
void init()
{
    e=0;
    memset(first+1,-1,sizeof(first[0])*n);
}
void add(int a,int b,int c)
{
    v[e]=b;
    t[e]=c;
    next[e]=first[a];
    first[a]=e++;
}
void read()
{
    int a,b,c;
    init();
    for(int i=1;i<n;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
        add(b,a,c);
    }
    for(int i=1;i<=n;i++)   scanf("%d",&val[i]);
}
int spfa()
{
    memset(d+1,0x3f,sizeof(d[0])*n);
    memset(vis+1,0,sizeof(vis[0])*n);
    d[1]=0;
    queue<int>q;
    int a,b;
    q.push(1);
    vis[1]=1;
    while(!q.empty())
    {
        a=q.front(),q.pop();
        if(a==n)    break;
        vis[a]=0;
        for(int i=first[a];~i;i=next[i])
        {
            b=v[i];
            if(d[b]>d[a]+t[i])
            {
                d[b]=d[a]+t[i];
                p[b]=a;
                if(!vis[b]) vis[b]=1,q.push(b);
            }
        }
    }
    return d[n];
}
void dfs(int a,int fa)
{
    dp[a][0]=val[a];
    for(int i=first[a];~i;i=next[i])
    {
        int b=v[i];
        if(b==fa || vis[b]) continue;
        dfs(b,a);
        for(int j=T;j>=0;j--)
        {
            for(int k=0;j-k-2*t[i]>=0;k++)
            {
                dp[a][j]=MAX(dp[a][j],dp[a][j-k-2*t[i]]+dp[b][k]);
            }
        }
    }
}
void solve()
{
    for(int i=1;i<=n;i++)   memset(dp[i],0xc3,sizeof(dp[0][0])*(T+1));
    memset(vis+1,0,sizeof(vis[0])*n);
    p[1]=0;
    for(int b=n;b;b=p[b])   vis[b]=1;
    for(int i=1;i<=n;i++)   if(vis[i])
    {
        dfs(i,0);
    }

    memset(ans,0xc3,sizeof(ans[0])*(T+1));
    ans[0]=0;
    for(int a=n;a;a=p[a])
    {
        for(int j=T;j>=0;j--)
        {
            for(int k=0;k<=j;k++)
            {
                ans[j]=MAX(ans[j],ans[j-k]+dp[a][k]);
            }
        }
    }
    int max=0;
    for(int i=0;i<=T;i++)   max=MAX(max,ans[i]);
    printf("%d\n",max);
}
int main()
{
    while(~scanf("%d%d",&n,&T))
    {
        read();
        T-=spfa();
        if(T<0)   puts("Human beings die in pursuit of wealth, and birds die in pursuit of food!");
        else    solve();
    }
    return 0;
}
复制代码
posted @   BeatLJ  阅读(220)  评论(0)    收藏  举报
编辑推荐:
· 微服务架构学习与思考:微服务拆分的原则
· 记一次 .NET某云HIS系统 CPU爆高分析
· 如果单表数据量大,只能考虑分库分表吗?
· 一文彻底搞懂 MCP:AI 大模型的标准化工具箱
· 电商平台中订单未支付过期如何实现自动关单?
阅读排行:
· .NET 阻止Windows关机以及阻止失败的一些原因
· 博客园2025新款「AI繁忙」系列T恤上架
· Avalonia跨平台实战(二),Avalonia相比WPF的便利合集(一)
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(6)
· C# LINQ 快速入门实战指南,建议收藏学习!
点击右上角即可分享
微信分享提示