hdu4276The Ghost Blows Light 树形dp+分组背包

//给一棵树,N个点每个点都有财宝,
//要在T时间从点1到点N且能得到的最大权值
//一遍dfs记录从1到N的路径所要经过的点x个
//然后通过这一条路径将这棵树拆开x个子树
//对于这x棵子树dp[i][j]表示以i点为根的子树用时间j
//最多能得到多少宝藏
//用一个分组背包可以做
#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
using namespace std ;
const int maxn = 110 ;
int dp[maxn][maxn*5] ;
int vis[maxn] ;
struct Edge
{
    int v , w ;
    int next ;
}edge[maxn<<1] ;
int head[maxn] ;
int nedge ;
int n , T ;
int a[maxn] ;
void addedge(int u  , int v , int w)
{
    edge[nedge].v = v ;
    edge[nedge].w = w ;
    edge[nedge].next = head[u] ;
    head[u] = nedge++ ;
}
int dfs(int u , int pre)
{
    if(u == n)
    {
        vis[n] = 1 ;
        return 0 ;
    }
    for(int i = head[u];i != -1 ; i = edge[i].next)
    {
        int v = edge[i].v ;
        if(v == pre)continue ;
        int tmp = dfs(v , u) ;
        if(tmp != -1)
        {
            vis[u] = 1 ;
            return tmp+edge[i].w ;
        }
    }
    return -1 ;
}
void dfss(int u , int pre)
{
    for(int i = head[u];i != -1 ; i = edge[i].next)
    {
        int v = edge[i].v ;
        if(v == pre || vis[v])continue ;
        dfss(v , u) ;
        for(int j = T;j >= 2*edge[i].w;j--)
           for(int k = 0;k <= j-2*edge[i].w;k++)
           dp[u][j] = max(dp[u][j] , dp[v][k] + dp[u][j-k-edge[i].w*2]) ;
    }
    for(int i = 0;i <= T;i++)
    dp[u][i] += a[u] ;
}
int main()
{
    //freopen("in.txt" , "r" , stdin) ;
    while(~scanf("%d%d" , &n , &T))
    {
        memset(head , -1 , sizeof(head)) ;
        memset(vis , 0 , sizeof(vis)) ;
        memset(dp , 0 , sizeof(dp)) ;
        nedge = 0 ;
        for(int i = 1;i < n;i++)
        {
            int u , v , w ;
            scanf("%d%d%d" , &u , &v , &w) ;
            addedge(u , v , w) ;
            addedge(v , u , w) ;
        }
        for(int i = 1;i <= n;i++)
        scanf("%d" , &a[i]) ;
        int tmp = dfs(1 , -1) ;
        if(tmp > T)
        {
            puts("Human beings die in pursuit of wealth, and birds die in pursuit of food!") ;
            continue ;
        }
        int ans = 0 ;
        for(int i = 1;i <= n;i++)
        if(vis[i])
        {
            dfss(i , -1) ;
            for(int j = T;j >= 0;j--)
              for(int k  = 0;k <= j;k++)
              dp[0][j] = max(dp[0][j] , dp[i][k] + dp[0][j-k])  ;
        }
        for(int i = 0;i <= T-tmp;i++)
        ans = max(ans , dp[0][i]) ;
        cout<<ans<<endl;
    }
    return 0 ;
}

你可能感兴趣的:(hdu4276The Ghost Blows Light 树形dp+分组背包)