背包(一般是\(01\)背包吧)与树形\(DP\)的结合,第一维通常是节点编号,第二维通常是背包体积.由子节点向父节点转移的时候,就是一个普通的背包问题.
\(T1\):选课/\(The\) \(more\), \(The\) \(Better\)
洛咕
HDU(多组数据)
题意:给定一个\(n\)个节点的森林,带点权,选\(m\)个点的最大点权和,要求选子节点必须先选父节点.
分析:新建一个虚根,森林变成树.套路地,设\(f[i][j]\)表示以\(i\)点为根的子树内选择\(j\)个点的最大点权和.先不考虑父节点必须选的话,\(f[u][j]=max(f[u][j],f[u][j-k]+f[v][k])\),最后再考虑要先选父节点,\(f[u][j]=f[u][j-1]+a[u]\).
#include
#include
#include
#include
#include
#include
#include
\(T2\):有线电视网
洛咕
POJ
题意:给定一棵带边权,叶子结点带点权的有根树.问从根结点出发使得权值和不为负最多能到达的叶子结点个数.
分析:套路地,设\(f[i][j]\)表示以\(i\)为根的子树内选出\(j\)个叶子节点的最大权值和.则\(f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]-w[i])\).
可以先预处理出每个节点的子树内有多少个叶子节点,那么对于叶子节点初始化\(f[i][1]=a[i].\),答案就是最大的\(j\)满足\(f[1][j]>=0\).
#include
#include
#include
#include
#include
#include
#include
\(T3\):重建道路
洛咕
POJ
题意:给定一棵\(n\)个节点的树,求留下一棵\(m\)个结点的子树,最少需要切断几条边?
分析:套路地,设\(f[i][j]\)表示以\(i\)为根的子树内留下\(j\)个节点最少需要切断的边数.则\(f[u][j]=min(f[u][j],f[v][k]+f[u][j-k])\),发现因为要考虑\(u->v\)这条边留不留的各种情况,然后就写挂了.
正难则反,设\(f[i][j]\)表示以\(i\)为根的子树内丢弃\(j\)个节点最少需要切断的边数.这个就可以\(f[u][j]=min(f[u][j],f[v][k]+f[u][j-k])\)这样转移了.初始化\(f[u][size[u]]=1\)(即相当于整颗子树都不要,直接切掉最上面那一条边即可).
然后还是设\(g[i][j]\)表示以\(i\)为根的子树内留下\(j\)个节点最少需要切断的边数.那么\(g[i][j]=f[i][size[i]-j]+(fa==root?0:1)\),即留下\(j\)个节点相当于丢掉\(size[i]-j\)个节点,然后如果\(i\)的父节点不是(虚)根节点\((0)\)的话,即这条边是存在的,需要切断.
#include
#include
#include
#include
#include
#include
#include
发现树上背包问题有个通用套路,状态一般都是\(f[i][j]\)表示以\(i\)为根的子树内.....\(j\)个节点的......,然后一般先要\(dfs\)预处理出一些东西,然后对叶子节点初始化,最后再\(dfs\)一次从下往上状态转移即可.