树DP训练专辑

No.1 hdu 2412 http://acm.hdu.edu.cn/showproblem.php?pid=2412

题意:n个人形成一个关系树,每个节点代表一个人,节点的根表示这个人的唯一的直接上司,只有根没有上司。要求选取一部分人出来,使得每2个人之间不能有直接的上下级的关系,求最多能选多少个人出来,并且求出获得最大人数的选人方案是否唯一。

分析:对于每一个点只有取或不去,但是有边的点一定不能取,和最大不连续子序列一样的状态,dp[i][0],dp[i][1],分别表示第i个点不取和取的方案数。问题是现在还要求方案唯一性,这个可以再转移的过程中记录是否有其他状态也可以达到当前最优值状态。

显然

叶子节点:dp[i][0]=0,dp[i][1]=1;

dp[i][0]=sum(max(dp[j][0],dp[j][1])) (j为i的子节点);

dp[i][1]=sum(dp[j][0]);


No.2 hdu 1054 http://acm.hdu.edu.cn/showproblem.php?pid=1054

题意:一城堡的所有的道路形成一个n个节点的树,如果在一个节点上放上一个士兵,那么和这个节点相连的边就会被看守住,问把所有边看守住最少需要放多少士兵

这题除了树dp,还可以用二分图的最小点覆盖做,这里只分析树dp

分析:对于每个点有两种状态,取或不取

可以很快的设出状态,dp[i][0],dp[i][1],表示不取i或取i时覆盖该子树需要的最少士兵。

dp[i][1]=sum(min(dp[i][0],dp[i][1]));

dp[i][0]=sum(dp[i][1]);


No.3 hdu 2196  http://acm.hdu.edu.cn/showproblem.php?pid=2196

这题好像以前遇到过,但是当时不会写,现在还是不会写,看了人家题解才明白的

题意:有很多台电脑相连(一颗树),对于每台电脑输出这台电脑到距离它最远的电脑的最长距离。

分析:对于每个节点,只有三种可能:1.以当前节点为根到叶子的距离。2.通过该节点的父亲的另一条最长子路径3,通过某个祖先的一条最长子路径。

对于第一种情况我们只要dfs一次就知道了。

对于第二种情况我们可以再第一种情况dfs的时候同时记录该节点的次短路长度,因为当前节点不能再和父亲节点最长路径上,如果在,那么就应该和父亲节点的次长路径相连。

第三种情况,我们只需要再dfs一次,然后每次从上一个父亲转移过来和第二种情况比较取最优即可

(建议画图研究)


No.4 hdu 1561 http://acm.hdu.edu.cn/showproblem.php?pid=1561

题意:中文的就不说了

分析:攻打一个城市必须要先攻打另一个城市,可以连一条边,要先攻打的城市作为父亲,不需要先攻打其他城市的都连0,这样就构成了一棵树。

可以设定一个状态 dp[i][j]表示以i为根节点的子树,攻打了j个城市的最大价值。

dp[i][j]=max(dp[i][j],dp[i][j-y]+dp[x][y])  ,dp[i][j]=c[j](x表示i的子树,1<=y<=m),注意每个子树只能够取一种物品,其中根节点必取,容量要刚好符合才能转移,这是一个分组背包的的模型,但是需要改进一下(加个判断,自己想)。


No.5 hdu 1520 http://acm.hdu.edu.cn/showproblem.php?pid=1520

这题和No.1这题是一样的,应该说更简单,不用求是否唯一。看情况其切吧


No.6 poj 3345 http://poj.org/problem?id=3345

题意:有n个城市,你要贿赂其中一些城市,使你的选票>=m,这些城市有写城市有附属城市,如果你贿赂了这个城市那么你能够得到这个城市及它附属城市的票。问你最小的贿赂金额

分析:其实和No.4有点像,如果你切完No.4然后切不出这题的话,说明你还没有弄清楚这类背包问题

状态和No.4是一样的,dp[i][j]表示以i为根节点的子树,取得j票的最小价值,转移基本是一样的。


No.7 zju 3326 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3326

题意:给你一颗大小为n权值树,然后求一颗大小为m子树(subtree不知道是不是这样翻译,应该和substring一样的),求这颗子树权值最大。

看完sample确定了子树的概念,就是相当于这颗树上的所有点可以有一条通路(就是连通分支),很快就能想到这题的解法,和前面的树dp+背包问题一样,只是要注意的是dp[i][j]这个表示的是以i为根的size为j的最大权值,其中i必取。

如果能够无压力的1y这题的话,基本上已经入门了。


No.8 poj 1947 http://poj.org/problem?id=1947

题意:求在一颗树中删去最小边数使得分离出来的子树中有一颗的大小为q的。

分析:状态不难设出,dp[i][j]表示以i为根的子树有j个点的最小删边数。一样用背包,但是转移都点恶心。

需要注意几点:

1.对于节点i的子节点K,那么要么和k相连,要么不连,如果当前容量j的最优值因为节点k更新了,那么就和k相连,不用删边,反之不相连,删除i-k这边。

2.dp[i][1]表示只有i一个节点,那么dp[i][1]=i的儿子个数。dp[i][sum]=0;表示i为节点的树没有删边;

3.对于寻找最优值,应该在DP过程中找到dp[i][p]的最小值,显然还要+1,因为要和父亲节点切断,因为这里wa了一次,然后在对于总的根节点不用+1,因为它没有父亲。


No.9 poj 2486 http://poj.org/problem?id=2486

题意:求你在树上移动k步所能获得的最多苹果数量

分析:这题状态要考虑回不回当前节点,所以要多加一维,dp[i][j][0]表示以i为根的走j步不返回i可以获得最多的苹果数,dp[i][j][1]表示以i为根的走j步返回i可以获得最多的苹果数。

状态设出,转移应该不难。也是背包模型。

对于dp[u][j][1]:必须是u的子节点v返回回来的那么dp[u][j][1]=max(dp[u][j][1],dp[u][j-k-2][1]+dp[v][k][1]);

对于dp[u][j][0]:

可以是前面的子树不返回,当前子树返回dp[u][j][0]=max(dp[u][j][0],dp[v][k][1]+dp[u][j-k-2][0]);

也可以是前面子树返回,当前子树不返回dp[u][j][0]=max(dp[u][j][0],max(dp[v][k][1],dp[v][k][0])+dp[u][j-k-1][1]);

最后结果在dp[u][0~k][0]和dp[u][0~k][1]中找。



你可能感兴趣的:(c)