转载陈述:
http://www.hawstein.com/posts/dp-novice-to-advanced.html
平面上有N*M个格子,每个格子中放着一定数量的苹果。你从左上角的格子开始, 每一步只能向下走或是向右走,每次走到一个格子上就把格子里的苹果收集起来, 这样下去,你最多能收集到多少个苹果。
解这个问题与解其它的DP问题几乎没有什么两样。第一步找到问题的“状态”, 第二步找到“状态转移方程”,然后基本上问题就解决了。
首先,我们要找到这个问题中的“状态”是什么?我们必须注意到的一点是, 到达一个格子的方式最多只有两种:从左边来的(除了第一列)和从上边来的(除了第一行)。 因此为了求出到达当前格子后最多能收集到多少个苹果, 我们就要先去考察那些能到达当前这个格子的格子,到达它们最多能收集到多少个苹果。 (是不是有点绕,但这句话的本质其实是DP的关键:欲求问题的解,先要去求子问题的解)
经过上面的分析,很容易可以得出问题的状态和状态转移方程。 状态S[i][j]表示我们走到(i, j)这个格子时,最多能收集到多少个苹果。那么, 状态转移方程如下:
S[i][j]=A[i][j] + max(S[i-1][j], if i>0 ; S[i][j-1], if j>0)
其中i代表行,j代表列,下标均从0开始;A[i][j]代表格子(i, j)处的苹果数量。
S[i][j]有两种计算方式:1.对于每一行,从左向右计算,然后从上到下逐行处理;2. 对于每一列,从上到下计算,然后从左向右逐列处理。 这样做的目的是为了在计算S[i][j]时,S[i-1][j]和S[i][j-1]都已经计算出来了。
伪代码如下:
python实现:
a = [[5, 8, 5, 7, 1, 8],
[1, 3, 2, 8, 7, 9],
[7, 8, 6, 6, 8, 7],
[9, 9, 8, 1, 6, 3],
[2, 4, 10, 2, 6, 2],
[5, 5, 2, 1, 8, 8],
[5, 9, 2, 6, 8, 3]]
vv = [[0] * 6 for i in range(7)]
for i, di in enumerate(a):
for j, dj in enumerate(di):
m = n = 0
if i > 0:
m = vv[i - 1][j]
if j > 0:
n = vv[i][j - 1]
vv[i][j] = a[i][j] + max(m, n)
for i, di in enumerate(a):
for j, dj in enumerate(di):
print a[i][j],
print
print '========='
for i, di in enumerate(vv):
for j, dj in enumerate(di):
print vv[i][j],
print