原文思路来自知乎,刚学DP的小白按照作者的思路打了一份代码,见:
动态规划的本质
我们先从一个情景开始:
假设小明有n本书放在一个大柜子里,每本书上都有编号,称为书籍编号,而它的放置顺序为顺序编号。
有一天妈妈看到小明书柜里的书书籍编号都是乱的,让他将编号按从大到小的顺序整理好。
但是小明想偷个懒,他想只整理一次,就将最多的书籍整理出来。
于是小明拿来另一个小柜子,目的是从大柜子里的书按照他们的顺序编号一本一本拿出来,使他们的书籍编号按递增顺序。设其中i为前几次把书抽出来, j为小柜子放进了多少本书,1<=j<=i,而f[i][j]记录前i次的最后一本书最小的书籍编号。能放的书不能超过小明拿的次数,因为每次只能抽出一本,拿出来的书可以放回,但后一次拿出来的书不能放到前一次拿出的书的前面。
小明最多能整理出多少书呢?
举个栗子
i 1 2 3 4 5 6
a[i] 1 7 2 8 3 4
可以看到第一本书的书籍编号是1,第二本书的书籍编号是7…
小明心想,不管三七二十一,先将第一本书放进小柜子再说。
于是 f[1][1] = a[1],代表第一次拿出了第一本书的编号,也就是将a[1]记录下来
在第二次拿书的时候,如果第二本书的书籍编号比f[1][1]小,那放进小柜子是不可能比完成递增的条件
那么f[2][1] = f[1][1] 表示前两次都只拿出了第一本书
很幸运,第二本书的编号是7,比a[1]大,于是小明高兴地把第二本书放进了柜子
并记录了 f[2][2]=a[2],表示前二次拿书最后一本为第二本书的书籍编号,聪明的小明还将
f[2][1] = a[1]记录了下来(读者可以思考一下为什么)。
在第三次拿书的时候,第三本书的编号是2,小明想起自己刚刚记录的f[2][1],也就是第一本的书籍编号,第三本可以放到第一本的后面,但它比第三本书的书籍编号7小,那么小明只有两个选择:
1.将第二本书放回大柜子,放进第三本书
2.将第三本书放回大柜子
机智的小明又想到:因为之后要放更多的书,那么放到最后的书籍编号要尽可能小
有:
if (a[i]>f[i-1][k-1]){
//将a[i]和序列中倒数第二项进行比较 如果比它大 可预选
if(a[i]>f[i-1][k]) ++k,f[i][k-1] = f[i-1][k-1],f[i][k] = a[i];
//如果比倒一大 增加序列的长度 将它放进原先的倒一后面 同时需要将倒二和倒一状态转移
else f[i][k-1] = f[i-1][k-1],f[i][k] = a[i];
//比倒数第一项小 将原先的倒一替换 同时也要记得转移倒二
}
// 将刚输入的数字与前i-1项 k-1长度最后一位的最小值进行比较
// 将a[i]和原先的最小值进行比较 同时增加序列的长度
else f[i