这两周普遍都有考试,耽误了几节课程,上周的总结也一起并在这周了,临近期末了,课程也结束了,这两周就学的背包问题,还有自己学习的区间dp。可能这部分相对于前面几部分还是比较好理解的,只要前面学的扎实,这部分应该也没有问题。
关于背包,有01背包,完全背包,多重背包,以及分组的背包问题。周六又看了区间dp,区间DP,顾名思义是在区间上DP,它的主要思想就是先在小区间进行DP得到最优解,然后再利用小区间的最优解合并求大区间的最优解。刚开始看01背包的时候,感觉这不就是贪心嘛,但是仔细一想还是有所区别的,贪心是在当前看来是最好的选择,动态规划思想就是解决子问题并记录子问题的解,这样就不用重复解决子问题了。
01背包的状态转移方程为
f[i][j] = max(f[i - 1][j], f[i - 1][j - w[i]] + v[j]),
f[i][j]:表示所有选法集合中,只从前i个物品中选,并且总体积不大于j的选法的集合,它的值是这个集合中每一个选法的最大值。 对于01背包问题选择方法的集合可以分成2种:
①不选第i个物品,并且总体积不大于j的集合所达到的最大值:f[i-1][j]
②选择1~i个物品,并且总体积不大于j的集合所达到的最大值f[i][j]
完全背包的状态转移方程:dp(i,j)=max(dp(i-1,j),dp(i,j-w)+v[i]),可以看出,完全背包的动态转移方程max中第二项为i,而不是i-1。而多重背包其实可以看成为01背包和完全背包的组合。也可以把多重背包问题只转换成01背包问题。分组背包,就是给你N组物品,然后每一组你至多选择一个物品(也可以不选),每个物品都有自己的体积和价值,现在给你一个容里为M的背包,让你用这个背包装物品,使得物品价值总和最大。
感觉背包问题课上讲的够多了,再加上区间dp之前投入的时间比较少,这次主要总结一下区间dp的问题。
解题思路:
既然要求解在一个区间上的最优解,那么把这个区间分割成一个个小区间,求解每个小区间的最优解,再合并小区间得到大区间即可。所以在代码实现上,我们可以枚举区间长度len为每次分割成的小区间长度(由短到长不断合并),内层枚举该长度下可以的起点,自然终点也就明了了。然后在这个起点终点之间枚举分割点,求解这段小区间在某个分割点下的最优解。
例题:
http://acm.hdu.edu.cn/showproblem.php?pid=4632
题意很简单,就是要求给定字符串的子序列为回文串的数量,由于数量巨大,于是得取模。
思路:
用dp[i][j]表示这一段里有多少个回文串,那首先dp[i][j]=dp[i+1][j]+dp[i][j-1],但是dp[i+1][j]和dp[i][j-1]可能有公共部分,所以要减去dp[i+1][j-1]。
如果str[i]==str[j]的话,还要加上dp[i+1][j-1]+1,因为首尾是可以组成一个回文子串的,而且首尾可以与中间任何一个回文子串组成新的回文子串 。
整数划分
题意:给出一个数n,要求在n的数位间插入(m-1)个乘号,将n分成了m段,求这m段的最大乘积。
思路:用dp[i][j]表示从第一位到第i位共插入j个乘号后乘积的最大值。根据区间DP的思想可以从插入较少乘号的结果算出插入较多乘号的结果。
状态转移方程为
dp[i][j]=max(dp[i][j],dp[k][j-1]*num[k+1][i])
其中num[i][j]表示从s[i]到s[j]这段连续区间代表的数值。
http://acm.hdu.edu.cn/showproblem.php?pid=4283
这是课件上的一道题,题意:有n个人排成一排要上台表演,每个人有一个屌丝值di。第k个上台表演的人,他的不满意度为(k-1)*di。现在有一个类似于栈的黑屋子,你可以让某些人进入这个黑屋子。这些人要按照排的顺序来,那么对于排在最前面的人,
就有两个选择:
(1)让他直接上台表演;
(2)让他暂时进黑屋子。
现在请你选择一个合理的调度顺序,使得最后的总不满意度最小?
思路:用dp[i][j]表示从第i个人到第j个人这段区间的最小花费(是只考虑这j-i+1个人,不需要考虑前面有多少人)那么对于dp[i][j]的第i个人,就有可能第1个上场,也可以第j-i+1个上场。考虑第K个上场
即在i+1之后的K-1个人是率先上场的,那么就出现了一个子问题 dp[i+1][i+k-1]表示在第i个人之前上场的
对于第i个人,由于是第k个上场的,那么屌丝值便是a[i]*(k-1) ,其余的人是排在第k+1个之后出场的,也就是一个子问题dp[i+k][j],对于这个区间的人,由于排在第k+1个之后,所以整体愤怒值要加上k*(sum[j]-sum[i+k-1]) 。
poj3280
题意:给你长度为m的字符串,其中有n种字符,每种字符都有两个值,分别是插入这个字符的代价,删除这个字符的代价,让你求将原先给出的那串字符变成一个回文串的最小代价。
思路:
因为删除一个字符和添加一个字符时等价的,所以考虑最小的一种即可,设dp[i][j]表示在区间i j范围内构成回文的最小花费,则:如果当前匹配的两个字符相等,即str[i] == str[j] 那么dp[i][j] = dp[i+1][j-1]。否则把左边添加删除一个右边的值,或者在右边添加删除一个左边的值 ,取一个最小的即可。即:dp[i][j]=min(dp[i+1][j]+cost[str[i]-'a'],dp[i][j-1]+cost[str[j]-'a']);
这周看的内容还是比较少的,这学期这门课也结束了,以后的路还很长,这段过程这算是难忘的回忆了,她带来的可能是一种新的学习方法,希望自己以后不忘初心,多督促督促自己,多写写博客,继续努力。