LintCode 800: Backpack IX (经典01背包问题,DP)

  1. Backpack IX
    中文English
    You have a total of n thousand yuan, hoping to apply for a university abroad. The application is required to pay a certain fee. Give the cost of each university application and the probability of getting the University’s offer, and the number of university is m. If the economy allows, you can apply for multiple universities. Find the highest probability of receiving at least one offer.

Example
Example 1:
Input:
n = 10
prices = [4,4,5]
probability = [0.1,0.2,0.3]
Output: 0.440

Explanation:
select the second and the third school. 

Example 2:
Input:
n = 10
prices = [4,5,6]
probability = [0.1,0.2,0.3]
Output: 0.370

Explanation:
select the first and the third school.

Notice
0<=n<=10000,0<=m<=10000

注意,该题是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.8 * 0.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
Output
0.51
Expected
0.44

我们看到
i = 0 j=8 0.81
这里就错了,因为学校0申请了2次!注意01背包和多重背包的j循环是从大到小,完全背包的j循环是从小到大!。

代码同步在
https://github.com/luqian2017/Algorithm

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值