九度 1499:项目安排(任务调度, 01背包变形)

题目描述:

小明每天都在开源社区上做项目,假设每天他都有很多项目可以选,其中每个项目都有一个开始时间和截止时间,假设做完每个项目后,拿到报酬都是不同的。由于小明马上就要硕士毕业了,面临着买房、买车、给女友买各种包包的鸭梨,但是他的钱包却空空如也,他需要足够的money来充实钱包。万能的网友麻烦你来帮帮小明,如何在最短时间内安排自己手中的项目才能保证赚钱最多(注意:做项目的时候,项目不能并行,即两个项目之间不能有时间重叠,但是一个项目刚结束,就可以立即做另一个项目,即项目起止时间点可以重叠)。

 

思路

1. 一道任务调度题, 为此专门翻了下算法导论, 回顾了上面那道贪心可解的调度题目. 那道题目给定任务的起始点, 求解最大的不想交子集. 动态规划的状态转移方程为

S(i,j) = max(S(i,k), S(k+1, j) ) 其中 S(i,j) 表示任务 i, j 之间的时间段. 贪心解法是按照任务的结束时间排序, 优先选择完成时间早的 

2. 编程之美上也有两道任务调度题. (1) n 个学生, m 个研究组, 每个学生可以参加自己喜欢的研究组, 如何安排见面会才能使得总时间最短. 解法是转化为图着色问题, 若一个学生同时对多个研究组感兴趣, 那么这些研究组之间各有直线连通, 用最少的色将图着色, 邻接的点颜色不同 (2) 有 N 场见面会要进行, 每一场见面会的起终时间给定, 求解至少需要多少场地才能让这些见面会能够正常进行. 解法是转化为区间图, 使用贪心算法求解, 尽量使用可以使用的, 序号最小的颜色着色

3. 这道题我本想着按照 (1) 的动规思路求解, 大致写了下状态转移方程, 觉得实现上可能会有难点, 尤其是判断某个区间内有哪些任务的问题, 觉得会很复杂. 取搜了下资料, 看到了两个关键字, 背包. 于是用背包的思路想了下, 写了状态转移方程.

dp[i] 表示第 i 项任务截止时间前能够获得的最大收益. dp[i] = max(dp[j]) + value[i]. j < i

o(n*n) 的时间复杂度, AC 了

4. 我记得以前做 kedebug 上的题目时也遇到过这种题目, 有时间要把任务调度的题目总结下. 记得去年 works application 给了一道笔试题就是任务调度的

 

代码

 

#include <iostream>
#include <stdio.h>
#include <vector>
#include <memory.h>
#include <algorithm>
using namespace std;

class Task {
public:
    int st, ed, value;
    Task(int _st, int _ed, int _value):st(_st), ed(_ed), value(_value) {
        //cout << st << " " << ed << " " << value << endl;
    }
    Task() {
        Task(0, 0, 0);
    }
    bool operator<(const Task &ths) const {
        return this->ed < ths.ed;
    }
};

int n;
int dp[10010];
vector<Task> tasks;

int main() {
    while(scanf("%d", &n) != EOF) {
        int st, ed, value;
        tasks.clear();

        for(int i = 0; i < n; i ++) {
            scanf("%d%d%d", &st, &ed, &value);
            tasks.push_back(Task(st, ed, value));
        }

        sort(tasks.begin(), tasks.end());
        memset(dp, 0, sizeof(int)*(n+2));

        dp[0] = 0;
        for(int i = 1; i <= n; i ++) {
            int start = tasks[i-1].st;
            dp[i] += tasks[i-1].value;
            int maxval = 0;
            for(int j = 0; j+1 < i; j ++) {
                if(tasks[j].ed > start) continue;
                maxval = max(maxval, dp[j+1]);
            }
            dp[i] += maxval;
        }

        int res =0;
        for(int i = 1; i <= n; i ++)
            res = max(res, dp[i]);
        printf("%d\n", res);
    }

    return 0;
}

 

你可能感兴趣的:(任务调度)