带权区间调度问题(Weighted Interval Scheduling)

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

解题思路

  1. 排序: 首先按照任务的结束时间 fi 对任务进行排序。这是因为对于每个任务 i,我们只需要考虑在它之前结束的任务,这样可以简化问题。

  2. 动态规划定义:

    • 定义数组 dp[i]表示选择前 i 个任务时的最大总权值。
    • 对于每个任务 i,我们需要找到它之前的最大不重叠任务的索引p(i)。
  3. 状态转移:

    • 如果选择任务 i,则 dp[i]=vi+dp[p(i)](p(i)) 是最后一个与任务 i兼容的任务的索引)。
    • 否则,dp[i]=dp[i−1]。
  4. 求解过程:

    • 对于每个任务 i,使用二分查找或线性查找找到最后一个与任务 i兼容的任务的索引 p(i)。
    • 更新 dp[i] 的值。
  5. 输出结果:

    最终的答案是 dp[n],其中 n是任务的总数。
  6. 说明:
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;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值