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从小到大排个序(这样后面想替换掉前面的才方便),然后开始枚举选和不选这件物品才可以保证得到正确的结果。

背包问题我的做法是画表格来推状态转移方程:
在这里插入图片描述

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 <iostream>
#include <algorithm>
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<<dp[i][j]<<" ";
        }
        cout<<endl;
    }*/
    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 <iostream>
#include <algorithm>
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;
}


  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Leo Bliss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值