1. 程式人生 > >再學動態規劃之 完全揹包

再學動態規劃之 完全揹包

暴力搜尋

考慮當前index 拿1張,2張,…時候,從index+1開始的最小張數。相加即可:

import sys
class Solution(object):

    def get_small_number(self, coins, index, amount):
        if amount == 0:
            return 0
        if amount < 0:
            return -1
        if index == len(coins)-1:
            if amount%coins[index] != 0
: return -1 else: return amount/coins[index] min_res = sys.maxint for i in range(amount/coins[index] + 1): back_amount = self.get_small_number(coins, index+1, amount-i*coins[index]) this_amount = back_amount + i if
back_amount == -1: this_amount = sys.maxint min_res = min(min_res, this_amount) return min_res def coinChange(self, coins, amount): """ :type coins: List[int] :type amount: int :rtype: int """ return -1 if self.
get_small_number(coins, 0, amount) == sys.maxint else self.get_small_number(coins, 0, amount)

記憶化搜尋

當前的問題就是,每次都沒有把結果記錄下來,導致重複計算。故 超時 比如[1 ,2, 5] 目標是 11 的時候。1拿2張,2拿0張 和 1拿0張,2拿1張;應該是一種情況。

import sys
res = dict()
class Solution(object):

    def get_small_number(self, coins, index, amount):
        if amount == 0:
            return 0
        if amount < 0:
            return -1
        if index == len(coins)-1:
            if amount%coins[index] != 0:
                return -1
            else:
                return amount/coins[index]
        if str(index)+'_'+str(amount) in res:
            return res[str(index)+'_'+str(amount)]
        min_res = sys.maxint
        for i in range(amount/coins[index] + 1):
            back_amount = self.get_small_number(coins, index+1, amount-i*coins[index])
            this_amount = back_amount + i
            if back_amount == -1:
                this_amount = sys.maxint
            min_res = min(min_res, this_amount)
        res[str(index)+'_'+str(amount)] = min_res
        return min_res


    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        res.clear()
        return -1 if self.get_small_number(coins, 0, amount) == sys.maxint else self.get_small_number(coins, 0, amount)

這次記憶化搜尋都超時了誒。。。

動態規劃

狀態轉移方程式: dp[i][j]=mint[0,1+j/coins]{t+dp[i1][jcoins[i]t]}dp[i][j]=min_{t\in[0,1+j/coins]}\{t+dp[i-1][j-coins[i]*t]\}

import sys
class Solution(object):
    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        arr = [[sys.maxint for _ in range(amount+1)] for _ in range(len(coins)+1)]
        for ix in range(len(coins)+1):
            arr[ix][0] = 0
        for i in range(1, len(coins)+1):
            for j in range(1, amount+1):
                res_min = arr[i-1][j]
                for t in range(1, j/coins[i-1]+1):
                    res_min = min(res_min, t+arr[i-1][j-coins[i-1]*t])
                arr[i][j] = res_min


        return -1 if arr[-1][-1] == sys.maxint else arr[-1][-1]

依然超時呢。還有什麼優化空間嗎? 我把遞推公式展開來寫,你就會發現所謂的優化空間了; dp[i][j]=min{dp[i1][j],1+dp[i1][jx],2+dp[i1][j2x]+...}dp[i][j] = min\{dp[i-1][j],1+dp[i-1][j-x],2+dp[i-1][j-2x]+...\} dp[i][jx]=min{dp[i1][jx],1+dp[i1][j2x],2+dp[i1][j3x]+...}dp[i][j-x] =min\{dp[i-1][j-x],1+dp[i-1][j-2x],2+dp[i-1][j-3x]+...\} 所以: dp[i][j]=min{dp[i1][j],1+dp[i][jx]}dp[i][j] = min\{dp[i-1][j],1+dp[i][j-x]\}

import sys
class Solution(object):
    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        arr = [[sys.maxint for _ in range(amount+1)] for _ in range(len(coins)+1)]
        for ix in range(len(coins)+1):
            arr[ix][0] = 0
        # arr[:][0] = 1
        for i in range(1, len(coins)+1):
            for j in range(1, amount+1):
                res_min = arr[i-1][j]
                if j - coins[i-1] >= 0:
                    res_min = min(res_min, 1+arr[i][j-coins[i-1]])
                arr[i][j] = res_min
        return -1 if arr[-1][-1] == sys.maxint else arr[-1][-1]