PTA 1002 Business (35分)

想试试PTA Top Level的难度,然后随便来了一题~

1002 Business (35分)

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

思路

很明显的01背包问题,我们知道普通01背包不论枚举物品的顺序如何对最终结果都是没有影响的。

而本题中由于deadline的限制,需要按照deadline从小到大排个序(这样后面想替换掉前面的才方便),然后开始枚举选和不选这件物品才可以保证得到正确的结果。

背包问题我的做法是画表格来推状态转移方程:
PTA 1002 Business (35分)_第1张图片

dp[i][j] 前i件物品中,当第i件放入容量为j的背包可以获得的最大利润。

需要注意的是 枚举的容量大于这件物品的deadline后:

  • 选择 dp[i][j-1]
  • 不选 dp[i-1][j]
dp[i][j] = max(dp[i-1][j],dp[i][j-1]);

代码

#include 
#include 
using namespace std;
const int N = 55;
const int MAX = 1e5;
struct Project
{
     
    int p,l,d;
    bool operator <(const Project x) const{
     
            return d < x.d;
    }
} a[N];

int dp[N][MAX];

int main()
{
     
    int n;
    cin>>n;
    int maxx = 0;
    for(int i = 1; i <= n; ++i)
    {
     
        cin>>a[i].p>>a[i].l>>a[i].d;
        maxx = max(maxx,a[i].d);
    }
    sort(a+1,a+n+1);
    for(int i = 1; i <= n; ++i)
    {
     
        for(int j = 1; j <= maxx; ++j)
        {
     
            if(j <= a[i].d)
                if(j - a[i].l < 0)
                    dp[i][j] = dp[i-1][j];
                else if(j - a[i].l == 0)
                    dp[i][j] = max(dp[i-1][j],a[i].p);
                else
                    dp[i][j] = max(dp[i-1][j],dp[i-1][j-a[i].l]+a[i].p);
            else
                dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
        }
    }
    /*for(int i = 1; i <= n; ++i)
    {
        for(int j = 1; j <= maxx; ++j)
        {
            cout<
    cout<<dp[n][maxx]<<endl;
    return 0;
}
/*
6
7 1 3
10 2 3
6 1 2
5 1 1
26 6 7
1 1 8
*/

尝试压缩空间复杂度

本题我A了后打算压缩空间复杂度,但是我发现上面提到的当超过deadline部分修改成:

dp[j] = max(dp[j],dp[j-1]);

因为是倒着算,当dp[j-1]在要用的时候却没有算出来(当背包容量超过当前枚举到的物品时的deadline,我打算选这个物品的时候)。。

应该是我处理方式不对,想了好久,还是压缩空间复杂度失败,留坑!!!

#include 
#include 
using namespace std;
const int N = 55;
const int MAX = 1e5;
struct Project
{
     
    int p,l,d;
    bool operator <(const Project x) const
    {
     
        return d < x.d;
    }
} a[N];

int dp[MAX];

int main()
{
     
    int n;
    cin>>n;
    int maxx = 0;
    for(int i = 1; i <= n; ++i)
    {
     
        cin>>a[i].p>>a[i].l>>a[i].d;
        maxx = max(maxx,a[i].d);
    }
    sort(a+1,a+n+1);
    for(int i = 1; i <= n; ++i)
    {
     
        for(int j = maxx; j > 0; --j)
        {
     
            if(j <= a[i].d)
            {
     
                if(j - a[i].l >= 0)
                    dp[j] = max(dp[j],dp[j-a[i].l]+a[i].p);
            }
            else
                dp[j] = max(dp[j],dp[j-1]); //这里不能这样!!!!
        }
    }
    cout<<dp[maxx]<<endl;
    return 0;
}


你可能感兴趣的:(动态规划)