以题目为例:
思路:动态规划 + 二分查找
/*
1. 构造dp数组,记dp[i]为前第i个任务能够获得的最大报酬
2. 对工作按结束时间排序
3. 找到第i个任务的开始时间,找到小于等于该时间的开始工作个数
4. 要么选择该任务,那么加上在该任务开始时间之前的最大报酬,要么不选择该任务,则为该任 务之前所有任务的报酬,dp[i] = max(dp[i - 1], dp[k] + get<2>(sortedSchedule[i - 1]))
*/
关键就是:
- 定义状态为前n个任务能够获得的最大报酬,而不是选择第n个任务能获得的最大报酬
- 状态转换方程,要么选择该任务,那么找到该任务之前的最多任务数量对应的dp值,然后累加,要么不选择该任务,那么值和上一个状态的dp值相同
代码实现
class Solution {
public:
int jobScheduling(vector<int>& startTime, vector<int>& endTime, vector<int>& profit) {
/*
1. 构造dp数组,记dp[i]为前第i个任务能够获得的最大报酬
2. 对工作按结束时间排序
2. 找到第i个任务的开始时间,找到小于等于该时间的开始工作个数
3. 要么选择该任务,那么加上在该任务开始时间之前的最大报酬,要么不选择该任务,则为该任 务之前所有任务的报酬,dp[i] = max(dp[i - 1], dp[k] + get<2>(sortedSchedule[i - 1]))
*/
int n = startTime.size();
tuple<int, int, int> sortedSchedule[n];
for (int i = 0; i < n; i++) {
sortedSchedule[i] = {startTime[i], endTime[i], profit[i]};
}
sort(sortedSchedule, sortedSchedule + n,
[](tuple<int, int, int>& a, tuple<int, int, int>& b) {
return get<1>(a) < get<1>(b);
});
int dp[n + 1];
memset(dp, 0, sizeof(dp));
int latestStartTime;
for (int i = 1; i <= n; i++) {
latestStartTime = get<0>(sortedSchedule[i - 1]);
int j = upper_bound(sortedSchedule, sortedSchedule + i - 1,
latestStartTime, [&](int a, tuple<int, int, int>& b) {
return a < get<1>(b);
}) - sortedSchedule;
dp[i] = max(dp[j] + get<2>(sortedSchedule[i - 1]), dp[i - 1]);
}
return dp[n];
}
};
相似问题: