动态规划刷题合集

P2051 [AHOI2009]中国象棋

这是一个十分不错的区间计数dp

首先我们会发现这个有两个维度,所以显然要降维,所以考虑一下把一行的状态进行压缩,也就是看一看可不可以把一行进行合并操作,于是我们就可以发现加入把一行看成一个,那么每一列最多只可以放两个,每一行可以增加两个,所以就可以设计一下状态dp[i][j][k]

表示放到第i行,有j列有一个棋子,有k列有两个棋子的方案数,所以就可以很顺利的感觉这个转移方程是要分类讨论的

一。一个子都不放

所以说dp[i][j][k] = dp[i-1][j][k];

二。只放一个棋子

这里又要分类讨论

一。放到了没有棋子的列上,所以dp[i][j][k] = dp[i-1][j-1][k] * (m -j -k + 1)
之后的乘法是用了乘法原理,也就是每一个空的列都可以放
二。放到了有一个棋子的列上,dp[i][j][k] = dp[i-1][j+1][k-1] * (j+1)

三。放两个棋子

在这里插入图片描述

之后这个题就ac了,还有不开longlong见祖宗

二P1453 城市环路

这是一个基环树dp

其实没有先环上dp,在树上dp那么麻烦,我们可以去动用人类智慧。

首先对于有一个环的树是不是首先要找到这个环,因为题目有十分美好的性质——》环上的每一个点都只有两条简单路径可以相互到达,所以说我们可以想一下,对于一个树上的两个节点,是不是在没连边的时候绝对不会在一个集合里面,换句话说,也就是假如说两个点之前在一个集合里面,又连了一条边,那么这一定是环上的两点 所以可以用并查集去找

之后就是树型dp,我们发现状态dp[i][0/1],十分好设计,至于转移也十分好, dp[i][1] = sum(dp[son][0]) dp[i][0] = sum(max(dp[son][1],dp[son][0]))

最后就是去处理环上找到的那两个点,设一个为s、一个为t,那么我们发现,这两个点是不是有可能同时不选,或者只选择一个,所以我们是不是可以进行两次dp,之后对于dp[s][0] , dp[t][0] 取max。为什么,首先在dfs(s)时候我们会自动 的选择最优的方案(这时候t选不选无所谓,我们只要最优解),所以dp[s][0]便满足了在一个不选(有可能两个都不选)的情况下最优的解,t同理

小结

这道题给了我两个启示
1.对于一个树的环可以用并查集去找
2.也就是问题的转化,其实就是一棵树一条边上的两个点不可以同时选,同时又加了两个点不可以同时选

三P2014 [CTSC1997]选课

这是一个类似于拓扑的题,但是我们发现这是一个树型的结构,所以可以直接树型dp

那么就是设计状态了,本来我想的状态是dp[i][j] 第i个节点子树中取j个数的最大值,之后我的转移脑残了,我想的是把所有子树都找出来,之后挨个匹配(初学者错误呜呜呜),之后就发现了自己的sb,所以转移方程其实比较好得出

dp[i][j] = max(dp[i][j],dp[son][k]+dp[i][j-k])

这里我们就要去枚举son j k 之后进行转移

那么下面就要思考

1.不要露状态,即循环的边界

我们强制i必须选择,那么j是不是有一个1的边界,下一个是不是就是m,考虑一下,显然是要从大到小取枚举。

k的话是不是只用从0到j-1(不可以到j,我们强制i必须选)

2.初始状态

那肯定就只有dp[i][1] = val[i]

3.复杂度

我们发现一共找n个节点,每一个节点内的循环上限是m2,所以总复杂度 n*m2 可以接受

启发

这个题还有一个问题就是这不是树,而是森林,我们可以建立一个0节点,也和题目的输入相符合,这样所有的m换一下换成m+1就好了

P1441 砝码称重

首先考虑一下对于几个数字如何高效求出可以拼接成那几个数字,其实这个就是一个背包的思想,我们设计状态dp[i][j] 就是第i个数字可不可以拼出来j,所以这个转移是不是很显然 dp[i][j] = dp[i-1][j-a[i]] 只要不漏状态,这是不是就是对的

之后考虑一下我们还有可能要去掉几个数字,发现这个去掉的数字个数很少,所有数字的总数也不多,那我们直接搜索找出来所有情况,之后在这种情况下dp就可以了,那么我们考虑如何搜索,其实也是套路,dfs(x,y)表示搜到第几个数,前面已经去掉了y个数字,之后对于这个数分类讨论去不去就好了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值