hdu4169_Wealthy Family_树形DP(2011美国区域赛)

首先推荐国家集训队论文一篇:《浅谈几类背包问题-徐持衡》

http://wenku.baidu.com/view/751dd3ee856a561252d36f44.html

质量很高的一道题,练习赛的时候没做出来,写成了二维的记忆化搜索,150000的数据量,铁定超时。

正确解法应该每个节点开一个一维临时背包,再有一个全局背包记录当前状态(子树)最优值,通过局部背包去优化当前状态下全局背包的值,这样能使状态从二维降到一维,另外,倒着枚举背包的体积可以做到无后效性,整体用记忆化搜索实现。

代码如下:

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
vector<int>son[150005];
int dp[305],K,N,w[150005];
const int max_int=10000000;
int dfs(int u)
{
    int t=0,cur[305];
    for (int i=1; i<=K; ++i)
        dp[i]=cur[i]=-max_int;
    dp[0]=cur[0]=0;
    int size=son[u].size();
    for (int i=0; i<size; ++i)
    {
        int now=dfs(son[u][i]);
        for (int j=t; j>=0; --j)
            for (int k=1; j+k<=K && k<=now; ++k)
                cur[j+k]=max(cur[j+k],cur[j]+dp[k]);
        t+=now;
    }
    if (!size)
        t=1;
    cur[1]=max(cur[1],w[u]);
    for (int i=0; i<=K; ++i)
        dp[i]=cur[i];
    return t;
}
int main()
{
    int i,j,root;
    while (scanf("%d%d",&N,&K)!=EOF)
    {
        for (i=0; i<=N; ++i)
            son[i].clear();
        int r;
        for (i=1; i<=N; ++i)
        {
            scanf("%d%d",&r,&w[i]);
            if (!r)
                root=i;
            else
                son[r].push_back(i);
        }
        dfs(root);
        if (dp[K]==-max_int)
            puts("impossible");
        else
            printf("%d\n",dp[K]);
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/Chierush/p/3120810.html