现在做一下动态规划的小结
1.背包问题
这是一类超级经典很基础的动态规划,好多动态规划题目都能用背包的方法写出或者是背包的变形.
这些在背包九讲中说的很清楚:链接(这是网上我随便找的一个讲的比较全的博客),这些背包问题给我的一个启发就是:转换,通过一系列的操作,转换为01背包
背包给我的感受:很大一部分状态的转移,都是新增一个量,然后结合之前的最优解进而推出当前最优解,而当决策是类似的要不要这个新增量的时候,这很明显就是背包类型或变形的题目.
比如 :
UVA10271_Chopsticks
这道题是以选取一对筷子中最短的作为决策,当然这也做的前提是要排序并且dp[i][j](i表示当前筷子数,j表示筷子的对数),如果当前为最短的a,那么最优解必然是前一个作为次短的b,c因为i>=j所以总会存在,做了这些铺垫之后就会发现这就是背包问题了
又比如:HDU3449_Consumer
这明显是背包问题,可是却比背包多出了一个限制:在购买一类物品的时候,我们必须先购买这类物品的篮子之类的.
这题的状态和转移很容易弄错,不能分别以买第i类商品花费j元所能得到的最多价值,然后再来一个总的dp[i][j]:而以第i类商品买不买为决策,这样做弊端是i类商品投入的花费范围太大,所以不能这样建立状态,重新换一个状态.
新状态:弄成dp[i][j][0]为前i类商品不买第i类商品得到的最优解(这个既是一个状态又是另一个状态的中转)
dp[i][j][1]为前i类商品并买第i类商品得到的最优解
剩下的状态转移就简单了
这题给我启发就是,有时候状态转移不好进行,可以把状态继续细分多加一维状态,方便转移,这样例子很多,比如树数形dp中多加一维[0]和[1](或更多)以区分父子节点,又比如完美服务中用来区分不同状态和之前我做过的一颗树种距离为k的有多少个点都能够用这种方法完美解决
还有一类背包变形是:UVA12589_Learning Vector
之前的背包当前选择对于之后的选择是没有影响的,可这题当前所选的向量对之后选择会有影响,因为向量形成的面积是由当前三角形面积加上由之前累加出来的高和现在的宽形成的矩形面积之和,所以在状态转移的时候必须多附加一个高度h的属性,为了高效用到了记忆化搜索
2.区间dp
这类题目,我做过最典型的就是
UVA1632_Alibaba
这道题目,刚开始做的时候难点就是没能够发现状态必然是一个连续的区间,所以以后做任何题目的时候一定要多思考,看有没有什么隐藏的限制条件(状态不合法或者重复考虑)或者是隐含的最优策略(和大臣握手or打怪or能够比较出优先级的),这些可能必须要多多做题才能发现隐藏的信息了
这题知道了状态怎么建立之后,转移就简单多了,不过这里需要强调一个很严肃的关于状态转移的问题:
初始化问题
.
a.在我们状态转移过程中会存在很多不合法状态,如何让他们不影响最终的结果呢,比如求啥最少最优的话,我们可以反向(求小初始化最大,求大初始化最小)初始化,不过这样有时也会出现错误,所以最保险的还是初始化之后,每次进行状态转移的时候判断是不是非法的状态,如果是的话,那么再一次反向初始化,就这样不断更新非法状态,最后就不怕有非法状态变成了"合法状态"了
b.状态转移过程中我们必须给出一些最基本的状态or极限状态,比如选物品时候dp[i][j],当物品i为0或者钱数j为0的时候他的状态是确定的基本的,所以要初始化.或者有一些甚至不符合实际情况,但是他转移之后却符合了实际情况,这样的为了统一,也会选择初始化
3.树形dp
这个题目我做过经典的就是UVA1218_Perfect Service
这道题目用到了上面所说的多开一维方便状态转移的技巧!!!
而且中间还用到了一些优化技巧,比如利用一些已知状态的来避免重复大量计算求和,这种优化往往很关键
4.状态压缩dp
这类题写的不多,遇到的经典有
Uva10817_Headmaster's Headache和旅行商问题
这个是一个弄懂就相对简单的状态压缩了,但却很经典值得仔细体味的一题
5.其他(
状态转移
)
这里说其他是因为这类题遇到的比较少,不足以枚举
和计数dp的状态转移什么分苹果有多少种分法,
递归搜索子局面的状态转移有
UVA1629---Cake slicing和我感觉超级神奇的
UVA1608_Non-boring sequences,这些递归子局面真心很神奇啊,分治算法的神奇之处啊
还有就是(给我的感觉就是扫描线)一个序列各种问题的dp,最长上升子序列or最长公共子序列,或者找这样一个符合某种关系的子序列如:
HDU3450_Counting Sequences or动窗口
UVA11572_Unique Snowflakes or
UVA1442_Cave,最大矩形面积等等.
动态规划做多了,感觉好多题目都是在动态转移
未完待续