九度笔记之 1499:项目安排 的两种动态规划方法比较

题目1499:项目安排

时间限制:1 秒

内存限制:128 兆

特殊判题:

提交:265

解决:70

题目描述:

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

输入:

输入可能包含多个测试样例。
对于每个测试案例,输入的第一行是一个整数n(1<=n<=10000):代表小明手中的项目个数。
接下来共有n行,每行有3个整数st、ed、val,分别表示项目的开始、截至时间和项目的报酬,相邻两数之间用空格隔开。
st、ed、value取值均在32位有符号整数(int)的范围内,输入数据保证所有数据的value总和也在int范围内。

输出:

对应每个测试案例,输出小明可以获得的最大报酬。

样例输入:
3
1 3 6
4 8 9
2 5 16
4
1 14 10
5 20 15
15 20 8
18 22 12
样例输出:
16
22

算法分析

       该题和

题目1463:招聘会
题目1434:今年暑假不AC

           属于同一类型题,每个对象本身包含了位置信息,所以在用动态规划更新的时间,dp[j]的j既可以为时间,表示在时间j做能产生的最大值 如题目1463:招聘会题目1434:今年暑假不AC里所讲的,以及本题中time output limit的算法 (为什么time output limit稍后分析),j也可以表示第几个项目,表示考虑前j个项目,所能产生的最大值,也就是本文AC的算法。

     首先要说一个函数

int findpm(int b,int e,int t)
     表示在排序的数组中(ps已经按照结束时间排序)查找项目结束时间 ps[i].endt<=t 的最大i. 具体参照

   在排序数组中查找特定条件数值的程序总结

    在动态规划更新过程中,当考虑第 i 个项目时,我们需要比较加入第i 个项目 和不加第i个项目 所能产生价值的最大值。

        int preid = findpm(0,i-1,ps[i].begt);
        maxP[i] = std::max(maxP[i-1],maxP[preid]+ps[i].val);

    关键点

       1. maxP[i-1]

        表示不加第i个项目,也就是前 i-1 个项目所能产生价值的最大值。这个比较好理解。

       2.maxP[preid]+ps[i].value

       当加入第i个项目后,之前项目中和第i个项目有重叠的项目肯定就不能做了,所以我们要查找前面不和第i 个项目重叠的前preid个项目 所能产生的最大价值。

       结束时间endt<= ps[i].begt的项目不和项目i重合,

       如何求前面不和项目i重合的项目所能产生的最大价值呢,由

maxP[i] = std::max(maxP[i-1],maxP[preid]+ps[i].val);
       知   maxP[j] >= maxP[j-1]

       所以我们只需求 满足ps[j].endt <= ps[i].begt 的最大j 也就是程序中的preid

       故 加入第i个项目所能产生的最大价值为  maxP[preid]+ps[i].val

   

       ***********为什么动态规划变量为时间时会产生时间超长呢*************

       为什么time output limit,本题和 题目1463:招聘会题目1434:今年暑假不AC 不同的地方在于1463、1434里面的时间为一天中的24小时,所以按照时间来动态规划的话,j的范围0<= j <=24,无论有多少个项目,dp的大小最大也为25。在本题中如果仍然按照时间来动态规划的话,j的maxT等于最晚的项目的结束时间,如果结束时间很晚的话,maxT很大,dp申请的空间也就很大,dp遍历所需时间也就长。

       for(int j = ps[i].endt;j<ps.back().endt+1;j++)
            dp[j] = temMax;


相似题目


源程序

AC的方法,计算第j个项目加入后 所能产生的最大值。

//============================================================================
// Name        : judo1499new.cpp
// Author      : wdy
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
 
#include <iostream>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
struct PRO{
    int begt;
    int endt;
    int val;
public:
    PRO(int begt_,int endt_,int val_):begt(begt_),endt(endt_),val(val_){};
 
};
std::vector<PRO> ps;
int maxP[10001];
int findpm(int b,int e,int t){
    int id = b-1;//Attention
    int mid;
    while(b<=e){ //ATTENTION  <=
        mid = (b+e)>>1;
        if(ps[mid].endt<=t){
            id = mid;
            b = mid+1;
        }else{
            e = mid-1;
        }
    }
    return id;
}
 
bool lessThan(const PRO& pl,const PRO& pr){
    return pl.endt<pr.endt;
}
void init(int n){
    ps.clear();
    for(int i =0;i<=n;i++)
        maxP[i]=0;
 
    int bt;
    int et;
    int val;
    ps.push_back(PRO(0,0,0)); //ATTENTION
    for(int i = 0;i<n;i++){
        scanf("%d %d %d",&bt,&et,&val);
        ps.push_back(PRO(bt,et,val));
    }
 
 
 
}
void getMax(int n){
    std::sort(ps.begin(),ps.end(),lessThan);
    for(int i = 1;i<n+1;i++){
        int preid = findpm(0,i-1,ps[i].begt);
        maxP[i] = std::max(maxP[i-1],maxP[preid]+ps[i].val);
    }
    printf("%d\n",maxP[n]);
}
 
void getMaxNew(int n){
    std::sort(ps.begin(),ps.end(),lessThan);
    int *dp = new int[ps.back().endt+1];
    for(int i = 1;i<n+1;i++){
        int temMax = std::max(dp[ps[i].endt],dp[ps[i].begt]+ps[i].val);
        for(int j = ps[i].endt;j<ps.back().endt+1;j++)
            dp[j] = temMax;
    }
    printf("%d\n",maxP[ps.back().endt]);
}
void judo(){
    int n;
    while(scanf("%d",&n)!=EOF){
        init(n);
        getMax(n);
    }
}
int main() {
    judo();
    //cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
    return 0;
}
 
/**************************************************************
    Problem: 1499
    User: KES
    Language: C++
    Result: Accepted
    Time:80 ms
    Memory:1944 kb
****************************************************************/


Time Limit Exceed

//============================================================================
// Name        : judo1499new.cpp
// Author      : wdy
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
 
#include <iostream>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
struct PRO{
    int begt;
    int endt;
    int val;
public:
    PRO(int begt_,int endt_,int val_):begt(begt_),endt(endt_),val(val_){};
 
};
std::vector<PRO> ps;
int maxP[10001];
int findpm(int b,int e,int t){
    int id = b-1;//Attention
    int mid;
    while(b<=e){ //ATTENTION  <=
        mid = (b+e)>>1;
        if(ps[mid].endt<=t){
            id = mid;
            b = mid+1;
        }else{
            e = mid-1;
        }
    }
    return id;
}
 
bool lessThan(const PRO& pl,const PRO& pr){
    return pl.endt<pr.endt;
}
void init(int n){
    ps.clear();
    for(int i =0;i<=n;i++)
        maxP[i]=0;
 
    int bt;
    int et;
    int val;
    ps.push_back(PRO(0,0,0)); //ATTENTION
    for(int i = 0;i<n;i++){
        scanf("%d %d %d",&bt,&et,&val);
        ps.push_back(PRO(bt,et,val));
    }
 
 
 
}
void getMax(int n){
    std::sort(ps.begin(),ps.end(),lessThan);
    for(int i = 1;i<n+1;i++){
        int preid = findpm(0,i-1,ps[i].begt);
        maxP[i] = std::max(maxP[i-1],maxP[preid]+ps[i].val);
    }
    printf("%d\n",maxP[n]);
}
 
void getMaxNew(int n){
    std::sort(ps.begin(),ps.end(),lessThan);
    int maxT = ps.back().endt;
    int *dp = new int[maxT+1];
    memset(dp,0,(maxT+1)*sizeof(int));
    for(int i = 1;i<n+1;i++){
        int temMax = std::max(dp[ps[i].endt],dp[ps[i].begt]+ps[i].val);
        for(int j = ps[i].endt;j<maxT+1;j++)
            dp[j] = temMax;
    }
    printf("%d\n",dp[maxT]);
}
void judo(){
    int n;
    while(scanf("%d",&n)!=EOF){
        init(n);
        getMaxNew(n);
    }
}
int main() {
    judo();
    //cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
    return 0;
}
 
/**************************************************************
    Problem: 1499
    User: KES
    Language: C++
    Result: Time Limit Exceed
****************************************************************/



普通背包问题
题目1364:v字仇杀队
题目1462:两船载物问题
题目1455:珍惜现在,感恩生活
题目1209:最小邮票数
题目1420:Jobdu MM分水果

项目安排类题目
题目1499:项目安排
题目1463:招聘会
题目1434:今年暑假不AC

资源无限求最大值的题目
题目1494:Dota


谷歌是最强大公司,没有之一,以前他们只在北美推出免费拨打语音电话,现在,终于轮到中国大陆了!

https://www.10086china.com/index.html?id=OTkxMzExMTMxMzU0MjA0Mg==




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值