题目1499:项目安排
-
题目描述:
-
小明每天都在开源社区上做项目,假设每天他都有很多项目可以选,其中每个项目都有一个开始时间和截止时间,假设做完每个项目后,拿到报酬都是不同的。由于小明马上就要硕士毕业了,面临着买房、买车、给女友买各种包包的鸭梨,但是他的钱包却空空如也,他需要足够的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
算法分析
该题和
属于同一类型题,每个对象本身包含了位置信息,所以在用动态规划更新的时间,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;
相似题目
普通背包问题
题目1364:v字仇杀队
题目1462:两船载物问题
题目1455:珍惜现在,感恩生活
题目1209:最小邮票数
题目1420:Jobdu MM分水果
项目安排类题目
题目1499:项目安排
题目1463:招聘会
题目1434:今年暑假不AC
资源无限求最大值的题目。
题目1494:Dota
源程序
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==