动态规划入门
一种学习编程的方法:抄别人的思路,抄别人的代码,然后,变成自己的。我在微博上看不少牛人都用过这样的方法,我以前也用,只不过没说。哈哈,这种方法适合比较难的算法。而,动态规划对我来说,就是比较难的了。算法,我觉得自己上道儿没多久。 一直听说动态规划是一种很牛的算法,确切的说是一种方法。我对它一直都是望而却步,一方面没有实际需求,另一方面总觉得自己学不会。这不要练内功,就硬着头皮开始,并且使出我上面的招数。 (本来前几天就要开始的,结果杭电acm上不去了,真郁闷,今天我不得不转战北大的acm。以后可能这儿吧,至少这里稳定啊,不会像杭电那样,总挂。这样,我这个春节回家,也算有点儿成绩了) 原来或多或少接触过动态规划,从别人的只言半语中,我觉得动态规划就是把一些需要重复计算的结果,存储起来,或者说缓存起来,这样,就可以不需要重复计算。但是,在实际运用中,我这招儿好想不灵,我觉得应该是问题本身的原因,如果大量重复得子问题,缓存的思想,肯定也能够提速不少的。既然如此,就说说正规的动态规划。
自顶向下的分析问题,自底向上的解决问题。这是动态规划方法的要诀,解决问题的时候,都应该按照这个来进行。在使用这个要诀进行分析之前,首先要明确,什么样的问题,能过用动态规划的方法解决:
- 最优子结构性质。意思是,要解决最优问题,可以通过找到其子问题的最优解来进行。这是一个递归的过程,但是学术一点儿说:要满足最优化原理
- 子问题重叠性质。就是在递归的过程中,每次遇到的子问题,不一定都是新的,可能已经计算过了,那这样再此计算就是浪费。

a[n][1] = max(a[n - 1][2]) + a[n][1]------①
递归形式出来了,要求得到a[n][1]节点的最大和,就要求得到a[n - 1][2](本来的值为2)节点的最大和,再加上a[n][1]本来的值就可以了。
再看a[n][3]怎么处理(a[n][2] = 0),递归形式如下:
a[n][3] = max(a[n - 1][2], a[n - 1][ 3 + 1]) + a[n][3]-------②
②与①有一点儿不一样。差别就在a[n][3]的父节点有两个,而 a[n][1]只有一个。
现在递归形式找到了,那么子问题重叠问题呢?通过①和②很明显的看出来,他们重复计算了a[n - 1][2]。其实,如果,我们把计算的过程都列出来,重复计算也是指数级增长的。可充分利用动态规划的长处。
核心代码如下:
for (int i = 1; i <= n; ++i) {
for (int j = 1; j < n + n; ++j) {
if (i == 1 || 0 == values[i][j]) continue;
int max = 0;
if (j > 1 && values[i - 1][j - 1] > max)
max = values[i - 1][j - 1];
if (j < n + n - 1 && values[i - 1][j + 1] > max)
max = values[i - 1][j + 1];
values[i][j] = max + values[i][j];
}
}
后面还有几个例子,今天一共ac了四个题目,会慢慢写出来分析。
【引用】
http://v.163.com/movie/2010/6/8/1/M6TCSIN1U_M6TCT9E81.html
http://zh.wikipedia.org/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92