写在前面,如果有更好的方法可以给博主分享一下么,木有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-1背包的变种,n相当于背包容量,prices相当于重量,probability数组稍加处理(1-probability[i])相当于价值,只不过价值之间相乘,取最小,表示一个学校也去不了的可能性,则1-一个学校也去不了的可能性表示至少可以去一个的可能性,则前面取最小,用1减去该值,则是最大。
题解
方法一:递归
_helper(self, w, v, index, c)函数,表示考虑求解考虑选择[0,index]中的学校,能得出的一个学校都去不了的最小可能性,递归函数,其中index,表示在可用money为c的情况下考虑选择[0, index]中的学校,c-表示可用的金额,故是最终结果,其表示在可用资金为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)