小明每天都在开源社区上做项目,假设每天他都有很多项目可以选,其中每个项目都有一个开始时间和截止时间,假设做完每个项目后,拿到报酬都是不同的。由于小明马上就要硕士毕业了,面临着买房、买车、给女友买各种包包的鸭梨,但是他的钱包却空空如也,他需要足够的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);
关键点
表示不加第i个项目,也就是前 i-1 个项目所能产生价值的最大值。这个比较好理解。
当加入第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 ****************************************************************/