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;

}

  

你可能感兴趣的:(HDU)