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; }