800. 揹包問題 IX

寫在前面,如果有更好的方法可以給博主分享一下麼,木有vip,看不到lintcode的題解,謝謝啦

題目描述

https://www.lintcode.com/problem/backpack-ix/description

你總共有n萬元,希望申請國外的大學,要申請的話需要交一定的申請費用,給出每個大學的申請費用以及你得到這個大學offer的成功概率,大學的數量是 m。如果經濟條件允許,你可以申請多所大學。找到獲得至少一份工作的最高可能性。

樣例

輸入:n = 10, prices = [4, 4, 5], probability = [0.1, 0.2, 0.3]

輸出:0.440

解釋:選擇低第2和第3個學校。

自己添加一點解釋:至少一份工作的可能性,是1 - 一份工作都沒有的可能性,即0.440 = 1 - (1 - 0.2) * (1 - 0.3)。其實這仍是經典0-1揹包的變種,n相當於揹包容量,prices相當於重量,probability數組稍加處理(1-probability[i])相當於價值,只不過價值之間相乘,取最小,表示一個學校也去不了的可能性,則1-一個學校也去不了的可能性表示至少可以去一個的可能性,則前面取最小,用1減去該值,則是最大。

題解

方法一:遞歸

_helper(self, w, v, index, c)函數,表示考慮求解考慮選擇[0,index]中的學校,能得出的一個學校都去不了的最小可能性,遞歸函數f(index, c)=min( f(index - 1,c), f(index - 1, c - w[i]) *(1- v[i]) ),其中index,表示在可用money爲c的情況下考慮選擇[0, index]中的學校,c-表示可用的金額,故f(len(prices) - 1, n)是最終結果,其表示在可用資金爲n的情況下,一個學校也去不了的最小可能性,用1-該值,則爲結果。

之前類比了經典0-1揹包問題,這邊解釋一下,遞歸終止條件,返回1,是因爲連乘,經典的返回0,是因爲連加。

if index < 0 or c < 0:
    return 1
class Solution:
    """
    @param n: Your money
    @param prices: Cost of each university application
    @param probability: Probability of getting the University's offer
    @return: the  highest probability
    """
    def backpackIX(self, n, prices, probability):
        if not prices or len(prices) != len(probability) or n <= 0:
            return 0
        res = 1 - self._helper(prices, probability, len(prices) - 1, n)
        return round(float(res), 2)

    def _helper(self, w, v, index, c):
        if index < 0 or c < 0:
            return 1
        res = 1
        for i in range(0, index + 1):
            res = min(res, self._helper(w, v, i - 1, c))
            if c - w[i] >= 0:
                res = min(res, self._helper(w, v, i - 1, c - w[i]) * (1 - v[i]) )
        return res

方法二:記憶化搜索

class Solution:
    def __init__(self):
        self.memo = []

    def backpackIX(self, n, prices, probability):
        if not prices or len(prices) != len(probability) or n <= 0:
            return 0
        self.memo = [[-1] * (n + 1) for _ in range(len(prices))]
        res = 1 - self._helper(prices, probability, len(prices) - 1, n)
        return round(float(res), 2)

    def _helper(self, w, v, index, c):
        if index < 0 or c < 0:
            return 1
        if self.memo[index][c] != -1:
            return self.memo[index][c]
        res = 1
        for i in range(0, index + 1):
            res = min(res, self._helper(w, v, i - 1, c))
            if c - w[i] >= 0:
                res = min(res, self._helper(w, v, i - 1, c - w[i]) * (1 - v[i]) )
        self.memo[index][c] = res
        return res

方法三:動態規劃

class Solution:
    def backpackIX(self, n, prices, probability):
        if not prices or len(prices) != len(probability) or n <= 0:
            return 0

        dp = [[1] * (n + 1) for _ in range(len(prices))]

        for j in range(n + 1):
            if j >= prices[0]:
                dp[0][j] = 1 - probability[0]

        for i in range(1, len(prices)):
            for j in range(n + 1):
                dp[i][j] = dp[i -1][j]
                if j >= prices[i]:
                    dp[i][j] = min(dp[i][j], dp[i - 1][j - prices[i]] * (1 - probability[i]))

        res = 1 - dp[-1][-1]
        return round(float(res), 2)

 空間優化

class Solution:
    def backpackIX(self, n, prices, probability):
        if not prices or len(prices) != len(probability) or n <= 0:
            return 0

        dp = [1] * (n + 1)

        for i in range(0, len(prices)):
            j = n
            while j - prices[i] >= 0:
                dp[j] = min(dp[j], dp[j - prices[i]] * (1 - probability[i]))
                j -= 1

        res = 1 - dp[-1]
        return round(float(res), 2)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章