题目:
老师在开学第一天就把所有作业都布置了,每个作业如果在规定的时间内交上来的话才有学分。每个作业的截止日期和学分可能是不同的。例如如果一个作业学分为 10,要求在 6 天内交,那么要想拿到这 10 学分,就必须在第 6 天结束前交。
每个作业的完成时间都是只有一天。
输入
第一行一个整数N,表示作业的数量;
接下来N行,每行包括两个整数,第一个整数表示作业的完成期限,第二个数表示该作业的学分。
输出
输出一个整数表示可以获得的最大学分。保证答案不超过 C/C++ 的 int 范围。 范围:
思路:
如果仅仅按照时间的紧迫程度来排列,那么有些情况就会不符合最优情况,如
4
1 3
2 4
3 9
3 8
该情况按时间排序的学分为16,但实际最大学分为21。
要满足最优解,既要看时间的紧迫程度,又要看一次学分的数值。
我们要做的就是尽量把学分大的作业在它的时间限制之内完成,如果有空余再去完成学分少的作业,而完成学分大的作业时也要满足从后往前的原则,这样才能有更多的空余给那些时间紧迫但学分少的作业留出时间完成。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct work{
int day;int fen;
}w[1000006];
bool cmp(work x,work y){
return x.fen>y.fen;
}
int b;//优化算法时间所用,用来记录从1~b已经都有安排了,不能再安排任务,
如果时间比它小需要直接跳过不再考虑
int d[800000];int ans;
int main()
{int n;cin>>n;
for(int i=0;i<n;i++){
scanf("%d%d",&w[i].day,&w[i].fen);
}//输入数据
sort(w,w+n,cmp);//按照学分从大到小排序
for(int i=0;i<n;i++){
if(w[i].day<=b)continue;//跳过的情况
for(int j=w[i].day;j>0;j--)//从后往前挨个考虑
{
if(d[j]==0)//该天没有安排任务的情况下
{d[j]=1;ans+=w[i].fen;//把该天计算入学分之内
break;//已经安排好了,跳出循环}
if(j==1) b=w[i].day;//到最后仍然没有位置了,说明从1~b已经排满,记录该种情况
}
}
cout<<ans;
return 0;
}