题目

原题链接
{% fold 点击显/隐题目 %}

As the manager of your company, you have to carefully consider, for each project, the time taken to finish it, the deadline, and the profit you can gain, in order to decide if your group should take this project. For example, given 3 projects as the following:

Project[1] takes 3 days, it must be finished in 3 days in order to gain 6 units of profit.

Project[2] takes 2 days, it must be finished in 2 days in order to gain 3 units of profit.

Project[3] takes 1 day only, it must be finished in 3 days in order to gain 4 units of profit.

You may take Project[1] to gain 6 units of profit. But if you take Project[2] first, then you will have 1 day left to complete Project[3] just in time, and hence gain 7 units of profit in total.
Notice that once you decide to work on a project, you have to do it from beginning to the end without any interruption.

Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N(<=50), and then followed by N lines of projects, each contains three numbers P, L, and D where P is the profit, L the lasting days of the project, and D the deadline. It is guaranteed that L is never more than D, and all the numbers are non-negative integers.

Output Specification:
For each test case, output in a line the maximum profit you can gain.

Sample Input:
4
7 1 3
10 2 3
6 1 2
5 1 1

Sample Output:
18

{% endfold %}

解析

01背包问题,需要注意的是对于某个项目,是还是不选
按照动态规划问题的套路,先找维度物品的序号任务期限
也即dp[i][j]为前i个任务在j天内能达到的最大收益。

根据背包问题的两种情况,有:
选:dp[i][j] = dp[i-1][j-pro.l] + pro.p
不选:dp[i][j] = dp[i-1][j]
很显然,如果要选择,存在两个条件:

  1. j-pro.l > 0
  2. j <= pro.d

根据样例可以发现,对于一群项目,我们应该优先处理deadline较前的任务(贪心的思想)

最后,将所有的dp值中最大的取出来即可
因为存在由于deadline的限制导致最大值不在边界的情况。如:

3
2 4 5
1 2 9
9 1 2

可以使用滚动数组再次压缩dp数组,不过内存给的比较大,没有压缩

代码

C++解法

{% fold 点击显/隐代码 %}

#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;

#define Log(format, ...) // printf(format, ##__VA_ARGS__)

struct Node {
    int p, l, d;
    Node(int _p = 0, int _l = 0, int _d = 0) : p(_p), l(_l), d(_d) {}
    void read() {
        scanf("%d%d%d", &p, &l, &d);
        Log("read %d %d %d\n", p, l, d);
    }
    bool operator<(const Node &rhs) const {
        if (d == rhs.d)
            return l < rhs.l;
        return d < rhs.d;
    }
};

const int maxn = 55;

Node projects[maxn];

int main() {
    int n;
    scanf("%d", &n);

    int maxd = 0;
    for (int i = 1; i <= n; ++i) {
        projects[i].read();
        maxd = max(maxd, projects[i].d);
    }
    Log("maxd %d\n", maxd);

    int **dp = new int *[n + 1];
    for (int i = 0; i <= n; ++i) {
        dp[i] = new int[maxd + 1];
        memset(dp[i], 0, sizeof(int) * (maxd + 1));
    }

    sort(projects + 1, projects + 1 + n);

    int maxProfit = 0;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= maxd; ++j) {
            dp[i][j] = dp[i - 1][j]; // 不选
            Node pro = projects[i];
            if (j - pro.l >= 0 && j <= pro.d)
                dp[i][j] = max(dp[i][j], dp[i - 1][j - pro.l] + pro.p); // 选
            maxProfit = max(maxProfit, dp[i][j]);
            Log("dp[%d][%d] = %d\t(%d,%d,%d)\n", i, j, dp[i][j], pro.p, pro.l,
                pro.d);
        }
    }

    printf("%d\n", maxProfit);

    for (int i = 0; i <= n; ++i)
        delete[] dp[i];
    delete[] dp;

    return 0;
}

{% endfold %}