题目概述
原题叙述
ZJM 有 n 个作业,每个作业都有自己的 DDL,如果 ZJM 没有在 DDL 前做完这个作业,那么老师会扣掉这个作业的全部平时分。
所以 ZJM 想知道如何安排做作业的顺序,才能尽可能少扣一点分。
INPUT
输入包含T个测试用例。输入的第一行是单个整数T,为测试用例的数量。
每个测试用例以一个正整数N开头(1<=N<=1000),表示作业的数量。
然后两行。第一行包含N个整数,表示DDL,下一行包含N个整数,表示扣的分。
OUTPUT
对于每个测试用例,您应该输出最小的总降低分数,每个测试用例一行。
输入样例
3
3
3 3 3
10 5 1
3
1 3 1
6 2 3
7
1 4 6 4 2 4 3
3 2 1 7 6 5 4
输出样例
0
3
5
备注
上方有三组样例。
对于第一组样例,有三个作业它们的DDL均为第三天,ZJM每天做一个正好在DDL前全部做完,所以没有扣分,输出0。
对于第二组样例,有三个作业,它们的DDL分别为第一天,第三天、第一天。ZJM在第一天做了第一个作业,第二天做了第二个作业,共扣了3分,输出3。
题目重述
有n个DDL,他们都有一个固定的结束时间和分值,只要在结束时间之前完成就可以获得相应的分数。但与传统的分值贪心问题不同的是,完成每个DDL需要的时间是相同的都为1天。
由于输入比较复杂进行一下说明方便后面的解题:
第一行:要处理的数据样例个数
第二行:第一组样例的数据个数
第三行:每个DDL的结束的时间
第四行:每个DDL的分值
后面部分就是第二行到第四行的循环(样例说明见题目备注)
解题思路
题目比较明显就是一道贪心算法的题目。但是要注意的有下面几个点:
1、DDL在结束的那一天完成是可以获得积分的。
2、完成每个DDL的花费是相同的(一天),但是收获并不相同(不同积分)。
3、题目要求的是求出最少的扣分,也可以理解为得到最多的分数。
根据上面的三个点,我们就可以开始建立贪心策略了,由于是等花费,不用再考虑时间段带来的问题,只需要尽可能安排分数较高的DDL。为了保证在安排时对其他DDL的影响最小,我们采用倒叙安排从最后一天开始安排能够安排的DDL中分值最高的。
有趣的是,虽然题面简单,该题目通过改变数据量的大小也能一定程度上加大难度:
可以从下面两个角度思考问题:
如果数据区域是1e3即1000,选择什么实现方法?
如果数据区域增加到1e6 ,前面的方法还会奏效么?又该使用什么算法呢?
很明显1e3的数据范围,O(n^2)的时间复杂度是完全可以接受的。我们可以暴力的进行求解,也就是首先按照分值排序,然后在每次的选择时都遍历一遍DDL,选择当前可以安排且没有被安排过的,且分值最大的进行安排。这种算法虽然笨重,但是数据较少且想不到好的优化方法时,不失为一种备用的方案。
接下来是Problem 2,数据量提升到了1e6,经过简单计算可以知道O(n^2)的时间复杂度一定会爆掉。在不重构的算法的前提下,我们可以在前面算法的基础上进行优化。经过分析可知,Problem 1的算法浪费了大量的时间复杂度在选DDL的过程中。但实际上,我们的实质需求只是选出最大分数的DDL。在选最大值的算法优化方面,堆是一种简便且高效的方法,引入大根堆即可将时间复杂度将至O(logn),完成题目需求。
题目源码
这里我们只列出了Problem 1的解法,Problem 2等待你的补充。
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
struct ddl
{
int time;
int score;
int flag;
bool operator<(ddl & a)
{
return score>a.score;
}
}a[1010];
int main()
{
int number=0;
scanf("%d",&number);
for(int i=0;i<number;i++)
{
int all_score=0;
int end_time=0;
int choose_score=0;
int group=0;
scanf("%d",&group);
for(int j=0;j<group;j++)
{
a[j].flag=0;
a[j].score=0;
a[j].time=0;
scanf("%d",&a[j].time);
if(a[j].time>end_time)
end_time=a[j].time;
}
for(int j=0;j<group;j++)
{
scanf("%d",&a[j].score);
all_score+=a[j].score;
}
sort(a,a+group);
for(int k=end_time;k>=1;k--)
{
for(int q=0;q<group;q++)
{
if(a[q].flag==0 && a[q].time>=k)
{
a[q].flag=1;
choose_score+=a[q].score;
break;
}
}
}
printf("%d\n",all_score-choose_score);
}
}