LintCode 800: Backpack IX (經典01揹包問題,DP)
注意,該題是01揹包問題的變種,不是完全揹包問題!因為每個學校只能申請一次!
class Solution { public: /** * @param n: Your money * @param prices: Cost of each university application * @param probability: Probability of getting the University's offer * @return: the highest probability */ double backpackIX(int n, vector<int> &prices, vector<double> &probability) { vector<double> dp(n + 1, 1.0); //dp[x] is the min probability that no one offer is received when money x are used. int count = prices.size(); for (int i = 0; i < count; ++i) { //for (int j = prices[i]; j <= n; ++j) { //錯誤! for (int j = n; j >= prices[i]; --j) { dp[j] = min(dp[j], dp[j - prices[i]] * (1.0 - probability[i])); //cout<<"i = "<<i<<" j="<<j<<" "<<dp[j]<<endl; } } return 1 - dp[n]; } };
以 Input 10 [4,4,5] [0.1,0.2,0.3] 為例,則輸出為: i = 0 j=10 0.9 i = 0 j=9 0.9 i = 0 j=8 0.9 i = 0 j=7 0.9 i = 0 j=6 0.9 i = 0 j=5 0.9 i = 0 j=4 0.9 i = 1 j=10 0.72 i = 1 j=9 0.72 i = 1 j=8 0.72 i = 1 j=7 0.8 i = 1 j=6 0.8 i = 1 j=5 0.8 i = 1 j=4 0.8 i = 2 j=10 0.56 //min(dp[10]=0.72, dp[5](1-price[2])=0.80.7) i = 2 j=9 0.56 i = 2 j=8 0.7 i = 2 j=7 0.7 i = 2 j=6 0.7 i = 2 j=5 0.7 Output 0.44
這個0.56是怎麼來的呢?我們要讓最終答案(0.44)儘量大,那麼dp[10]=0.56就要儘量小。
注意,這裡的j迴圈一定要是從大到小。為什麼呢? 我們將j迴圈換成下面的程式碼: for (int j = prices[i]; j <= n; ++j) { //注意,這是錯的! 以 上面的Input為例,則輸出為:
i = 0 j=4 0.9 i = 0 j=5 0.9 i = 0 j=6 0.9 i = 0 j=7 0.9 i = 0 j=8 0.81 i = 0 j=9 0.81 i = 0 j=10 0.81 i = 1 j=4 0.8 i = 1 j=5 0.8 i = 1 j=6 0.8 i = 1 j=7 0.8 i = 1 j=8 0.64 i = 1 j=9 0.64 i = 1 j=10 0.64 i = 2 j=5 0.7 i = 2 j=6 0.7 i = 2 j=7 0.7 i = 2 j=8 0.64 i = 2 j=9 0.56 i = 2 j=10 0.49
注意01揹包和多重揹包的j迴圈是從大到小,完全揹包的j迴圈是從小到大!。