劍指offer(47):禮物的最大值(動態規劃詳解,python版)

本博客主要內容爲圖書《劍指offer》第二版47 題的解題思路及代碼。方法可能還有不足之處,歡迎大家討論評論。

1. 題目描述

  在一個 m*n 的棋盤中的每一個格都放一個禮物,每個禮物都有一定的價值(價值大於0).你可以從棋盤的左上角開始拿各種裏的禮物,並每次向左或者向下移動一格,直到到達棋盤的右下角。給定一個棋盤及上面個的禮物,請計算你最多能拿走多少價值的禮物?

  比如說現在有一個如下的棋盤,

在這個棋盤中,按照(1,12,5,7,7,16,5)的順序可以拿到總價值最大的禮物。

2. 題目分析

  我們首先使用遞歸的思路進行分析,當求解到達右下角時禮物的最大總價值時,可以通過如下的遞推關係進行計算

f(i,j)=ma(f(i1,j),f(i,j1))+g(i,j)

其中 f(i,j) 是要求解的最大值, f(i,j1) 到達 (i,j) 點左邊點時得到最大禮物價值,而 f(i1,j) 是到達 (i,j) 點上邊點時得到最大禮物價值,g(i,j)(i,j) 點禮物的價值。同歸地推關係式可以使用遞歸的方法進行求解,但是在使用遞歸求解的過程中會重複求解許多的值,所以這個時候就應該使用動態規劃的方式進行求解。也就是說分析的過程如上,是從上到下遞歸地分析;而求解過程是從下到上循環地求解。

  一個很直觀的想法是,我們將每一步求解出的結果都保存在一個矩陣中。那麼在這個問題中就要有一個和原始矩陣等大的矩陣進行存儲,但是實際上只需要一個與列數相同維數的一維數組就夠了。爲什麼存儲這麼少的就夠了呢。

  在動態規劃求解這個問題的時候,我們找出到達每一行中每個位置的最大值,在求解第一行的時候,很明顯只能一直向右走,對於第二行的一個數字,很明顯只能從 (0,0) 走到 (0,1) ,這個還是先用與原始矩陣同樣大的矩陣進行分析,如下所示

這裏寫圖片描述

在上圖中,如果要求到達 a 點的禮物的最大值,它只與左邊的值和它上面的值有關,所以在計算 a 之前就可以將 1 去掉了,因爲後面的計算都不會用到 a 的。同理計算出 a 點的最大值之後就可以將 11 替換掉了,因爲再求 b 的時候不會再用到。分析到這裏我們就可以發現,並不需要一個與原始矩陣等大的矩陣來存儲中間計算的值,只需要一個與列數相同的一維向量即可。

3. 代碼實現

class Solution:
    def getmaxValue(self, values, rows, cols):
        if not values or rows<=0 or cols <=0:
            return 0
        # 用於存放中間數值的臨時數組
        temp = [0] * cols

        for i in range(rows):
            for j in range(cols):
                left = 0
                up = 0

                if i > 0:
                    up = temp[j]
                if j > 0:
                    left = temp[j-1]
                temp[j] = max(up,left) + values[i*rows+j]
        return temp[-1]
s = Solution()
a = s.getmaxValue([1,10,3,8,12,2,9,6,5,7,4,11,3,7,16,5],4,4)

參考文獻

  1. 何海濤. 劍指Offer.第2版[M]. 電子工業出版社, 2014.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章