Description
每一个任务都有三个属性:开始时间s、结束时间f以及所产生的价值v一个任务的s到f这段时间称为其执行时间,如果两个任务的执行时间不重叠,则称它们是兼容的本题将给出若干任务及其属性,求彼此兼容且权重最大的任务子集,输出该子集所有任务产生的总价值。
Input
输入有1+n行;第1行为任务数量;剩余n行每行为一个任务的开始时间、结束时间和所产生的价值,以空格隔开,例如:
4
1 2 50
3 5 20
6 19 100
2 100 200
Output
输出应为一个数,即彼此兼容且权重最大的任务子集中所有任务产生的总价值,如
250
Sample Input 1
4 1 2 50 3 5 20 6 19 100 2 100 200
Sample Output 1
250
解题思路
-
排序: 首先按照任务的结束时间 fi 对任务进行排序。这是因为对于每个任务 i,我们只需要考虑在它之前结束的任务,这样可以简化问题。
-
动态规划定义:
- 定义数组 dp[i]表示选择前 i 个任务时的最大总权值。
- 对于每个任务 i,我们需要找到它之前的最大不重叠任务的索引p(i)。
-
状态转移:
- 如果选择任务 i,则 dp[i]=vi+dp[p(i)](p(i)) 是最后一个与任务 i兼容的任务的索引)。
- 否则,dp[i]=dp[i−1]。
-
求解过程:
- 对于每个任务 i,使用二分查找或线性查找找到最后一个与任务 i兼容的任务的索引 p(i)。
- 更新 dp[i] 的值。
-
输出结果:
最终的答案是 dp[n],其中 n是任务的总数。 - 说明:
dp[i] = max(dp[i - 1], value_i + (p[i - 1] != -1 ? dp[p[i - 1] + 1] : 0));
p[i-1]表示
这里即选不选第i个任务,不选就是dp[i-1],选的话,当前任务的价值加上之前已经选上的任务的最大价值。
p(i-1)表示与第i个任务相兼容的任务索引,由于p(x)是从0开始,其下标与第几个任务是索引差1.
7.代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 定义任务结构
struct Task {
int start;
int finish;
int value;
};
// 比较函数,用于按结束时间排序
bool compare(Task a, Task b) {
return a.finish < b.finish;
}
// 查找最后一个不重叠的任务
int findCompatibleTask(const vector<Task>& tasks, int index) {
for (int j = index - 1; j >= 0; j--) {
if (tasks[j].finish <= tasks[index].start) {
return j;
}
}
return -1; // 没有兼容的任务
}
// 带权区间调度函数
int weightedIntervalScheduling(vector<Task>& tasks) {
// 按结束时间排序
sort(tasks.begin(), tasks.end(), compare);
int n = tasks.size();
vector<int> dp(n + 1, 0);
vector<int> p(n);
// 计算每个任务的兼容任务索引
for (int i = 0; i < n; i++) {
p[i] = findCompatibleTask(tasks, i);
}
// 动态规划计算最大权值
for (int i = 1; i <= n; i++) {
int value_i = tasks[i - 1].value;
dp[i] = max(dp[i - 1], value_i + (p[i - 1] != -1 ? dp[p[i - 1] + 1] : 0));
}
return dp[n]; // 返回最大权值
}
int main() {
int n;
cin >> n;
vector<Task> tasks(n);
for (int i = 0; i < n; i++) {
cin >> tasks[i].start >> tasks[i].finish >> tasks[i].value;
}
int maxValue = weightedIntervalScheduling(tasks);
cout << maxValue << endl;
return 0;
}