LintCode 273: Test Strategy (背包型DP好题)

273. Test Strategy

You have an exam, which lasts 120 minutes. There are multiple questions on the exam, and your answer order is not limited. There are three different strategies you can choose from for the question i:

 

Skip this question and get 0 points for no time.

Just do part of the problem. You would spend p[i] minutes and get part[i] points.

Do the whole problem. You would spend f[i] minutes and get full[i] points.

Given four arrays in turn: p, part, f, full, calculate the maximum number of points you can get.

 

Example

Sample 1:

Input sample: p=[20,50,100,5], part=[20,30,60,3], f=[100,80,110,10], full=[60,55,88,6]

Output sample: 94

Sample explanation: Of all the choices, choosing to complete the whole question 3 and the whole question 4 has the highest score. The whole of question 3 took 110 minutes to get 88 points, and the whole of question 4 took 10 minutes to get 6 points, so it took 120 minutes to get 94 points altogether.

 

Sample 2:

Input sample: p=[60,60], part=[30,30], f=[100,120], full=[40,60]

Output sample: 60

Sample explanation: You can choose doing part of the problem 1 and 2 or doing the whole of question 2. Either way you can get a maximum of 60 points in 120 minutes .

 

Clarification

We will run your code for 20times,. please ensure that you don't change the param in your function.

 

Notice

The number of examination questions is no more than 200 and at least 1.

Time spent on each question: 1 ≤ p[i] ≤ f[i] ≤ 120

Score of each question: 1 ≤ part[i] ≤ full[i] ≤ 100


解法1:
首先这题是01背包型DP。dp[i][j]表示前i道题花了时间j时所得到的最多分数。注意对i要分3种可能:不做,部分做和全部做。

class Solution {
public:
    /**
     * @param p: The time you choose to do part of the problem.
     * @param part: The points you choose to do part of the problem.
     * @param f: The time you choose to do the whole problem.
     * @param full: The points you choose to do the whole problem.
     * @return: Return the maximum number of points you can get.
     */
    int exam(vector<int> &p, vector<int> &part, vector<int> &f, vector<int> &full) {
        int n = p.size();
        vector<vector<int>> dp(n + 1, vector<int>(121, 0));
        
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= 120; ++j) {
                dp[i][j] = dp[i - 1][j]; // case 1: skip question i
                
                if (j >= p[i - 1]) { //case 2: partial question i
                    dp[i][j] = max(dp[i][j], dp[i - 1][j - p[i - 1]] + part[i - 1]);
                }
                
                if (j >= f[i - 1]) { //case 3: full question i
                    dp[i][j] = max(dp[i][j], dp[i - 1][j - f[i - 1]] + full[i - 1]);
                }
            }
        }
        
        return dp[n][120];
    }
};

解法2:滚动数组优化空间。
 

class Solution {
public:
    /**
     * @param p: The time you choose to do part of the problem.
     * @param part: The points you choose to do part of the problem.
     * @param f: The time you choose to do the whole problem.
     * @param full: The points you choose to do the whole problem.
     * @return: Return the maximum number of points you can get.
     */
    int exam(vector<int> &p, vector<int> &part, vector<int> &f, vector<int> &full) {
        int n = p.size();
        vector<vector<int>> dp(2, vector<int>(121, 0));
        
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= 120; ++j) {
                dp[i % 2][j] = dp[(i - 1) % 2][j]; // case 1: skip question i
                
                if (j >= p[i - 1]) { //case 2: partial question i
                    dp[i % 2][j] = max(dp[i % 2][j], dp[(i - 1) % 2][j - p[i - 1]] + part[i - 1]);
                }
                
                if (j >= f[i - 1]) { //case 3: full question i
                    dp[i % 2][j] = max(dp[i % 2][j], dp[(i - 1) % 2][j - f[i - 1]] + full[i - 1]);
                }
            }
        }
        
        return dp[n % 2][120];
    }
};

解法3:一维数组优化空间。

class Solution {
public:
    /**
     * @param p: The time you choose to do part of the problem.
     * @param part: The points you choose to do part of the problem.
     * @param f: The time you choose to do the whole problem.
     * @param full: The points you choose to do the whole problem.
     * @return: Return the maximum number of points you can get.
     */
    int exam(vector<int> &p, vector<int> &part, vector<int> &f, vector<int> &full) {
        int n = p.size();
        vector<int> dp(121, 0);
        
        for (int i = 1; i <= n; ++i) {
            for (int j = 120; j >= min(p[i - 1], f[i - 1]); --j) {
                //case 1: dp[j] = dp[j] skip question i
                if (j >= p[i - 1]) { //case 2: partial question i
                    dp[j] = max(dp[j], dp[j - p[i - 1]] + part[i - 1]);
                }
                
                if (j >= f[i - 1]) { //case 3: full question i
                    dp[j] = max(dp[j], dp[j - f[i - 1]] + full[i - 1]);
                }
            }
        }
        
        return dp[120];
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值