树形dp专题训练

树形dp真是十分精妙,感觉惨遭海虐,树形dp经常和背包一起出,分组背包之类的。还有很多独立集之类的概念。

HDU 4313

题意:给你一棵树,有k个点有危险,然后要切断一些边,让这些点之间都不相连,问最小花费多少

题解:树形dp,dp[u][0]表示u和下面所有的有危险的点都隔绝了,dp[u][1]表示和下面1个有危险的点相连

如果这个点是危险点,那么dp[u][1]=INF; dp[u][0]=∑(dp[v][0])+∑edge[i].c(v是危险点);

如果不是危险点,那么dp[u][0]就是全部切断,dp[u][1]就是要和一个危险点相连,可以先求出全部切断的,然后求一个最小的inc=切断-不切断,加上就行了

AC代码:http://paste.ubuntu.net/13574063/


HDU 3534

题意:给你一棵树,统计树里面直径的个数

题解:树形dp,要记录的东西比较多,dp[u][5],dp[u][0]记录u为根的最长路,dp[u][1]记录次长路,最长路和次长路是不同子树里的,dp[u][2]记录最长路的个数,dp[u][3]记录次长路的个数,dp[u][4]记录如果最长路和次长路相等的时候,有多少条经过u的最长边

要注意的就是最长次长相等的时候。

更新的话就是最长路次长路不用说,dp[u][2]=dp[v][2],dp[u][3]=dp[v][2],这是最长次长不相等的时候,如果相等,那么dp[u][2]+=dp[v][2];dp[u][4]+=dp[v][2]*dp[u][2];

最后先求出直径,然后枚举u,如果最长次长相等就+=dp[u][4],如果不相等就+=dp[u][2]*dp[u][3];

AC代码:http://paste.ubuntu.net/13574110/


HDU 4276

题意:给你一棵树,让你从1走到n,给你10点体力,然后走过多少距离就要消耗多少体力,然后如果重复走一条边就是要消耗两倍,点上有财富,求走出去获得的最大财富

题解:树形dp+分组背包orz

一开始直接用背包搞,怎么都wa,就是不明白

看了题解发现首先可以把最短路求出来,然后把最短路上的边权值都改为0,这样做背包的时候这条边就必选了,然后树形dp的时候,枚举当前点的体力,类似于背包,然后枚举在v点用了多少体力,dp[u][j]=max(dp[u][j-k-cost]+dp[v][k]);

财富有可能是0,所以dp初始化为-1,dp[u][0]=val[u];

总是掉坑里,感觉还需要多练习

AC代码:http://paste.ubuntu.net/13574164/


HDU 1561

题意:给你一些城堡,然后攻击,有些是可以直接攻击,有些得要干掉前置的才能干这个,每个城堡有财宝,可以干m个,问最多

题解:可以直接攻击的就往0连,建个有向的树,然后dp[u][1]=val[u];

分组背包 dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]);k<j

AC代码:http://paste.ubuntu.net/13574301/


HDU 4003

题意:给你一棵树,然后一个起点,扔下去k个机器人,要求k个机器人走遍整棵树的最小花费

题解:这题过的人挺多,但是感觉好难啊,搞了好久都没什么想法,

看了题解是分组背包+树形dp,但是搞不像,GG

因为这题机器人可以走回去,所以状态比较难想,但是有个细节我没有注意到

其实只有在走下去的机器人是1个的时候才有可能回上去。

为什么呢

设状态dp[u][i],表示i个机器人最后留在u为根的子树里,i==0时,表示有一个机器人走下去又回上去,i>0的时候,不可能有机器人回上来,因为如果有i+1个机器人走了下去,然后1个机器人回上去到u,再走到u的父亲,再走到另外个儿子,这样的花费大于下去i个机器人,一个走完了它自己的路,回到u,然后再走前面i+1走的路,这样比i+1个机器人下去少了一段从u到u的父亲的路

所以这样就能知道如何转移了

但是每个子树都需要走,所以可以先假设一个机器人下去再上来,然后用背包

for(int i=k;i>=0;i--){

     dp[u][i]+=dp[v][0]+2*edge[i].c;

     for(int j=1;j<=i;j++) dp[u][i]=min(dp[u][i],dp[u][i-j]+dp[v][j]+j*edge[i].c);

}

这样就可以初始化为0了,因为每次dp[u][i]已经不是0了,后面就算是0+dp[v][j]+j*edge[i].c也没事,这就类似于背包,不是最优解而已。(这段话是给自己看的)

AC代码:http://paste.ubuntu.net/13574640/




  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值