week 4 hw ddl 贪心

该博客介绍了一个关于如何根据DDL(截止日期)安排作业以最大限度减少得分损失的问题。作者提出了一种贪心算法,按DDL对作业排序,并使用最大堆优化策略。通过从DDL最后一天开始反向遍历并选择最高分作业,确保解决方案的有效性。博客提供了样例解释和代码实现,强调在贪心问题中寻找正确策略和高效数据结构的重要性。
摘要由CSDN通过智能技术生成

题意:

ZJM 有 n 个作业,每个作业都有自己的 DDL,如果 ZJM 没有在 DDL 前做完这个作业,那么老师会扣掉这个作业的全部平时分。
所以 ZJM 想知道如何安排做作业的顺序,才能尽可能少扣一点分。
请你帮帮他吧!

Input
输入包含T个测试用例。输入的第一行是单个整数T,为测试用例的数量。
每个测试用例以一个正整数N开头(1<=N<=1000),表示作业的数量。
然后两行。第一行包含N个整数,表示DDL,下一行包含N个整数,表示扣的分。
Output
对于每个测试用例,您应该输出最小的总降低分数,每个测试用例一行。

Sample Input

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

Sample Output
0
3
5

样例解释:
上方有三组样例。
对于第一组样例,有三个作业它们的DDL均为第三天,ZJM每天做一个正好在DDL前全部做完,所以没有扣分,输出0。
对于第二组样例,有三个作业,它们的DDL分别为第一天,第三天、第一天。ZJM在第一天做了第一个作业,第二天做了第二个作业,共扣了3分,输出3。


思路:

为了得到最多的分,我们可以采用贪心的思想,由于每道题的覆盖时长都为1,因此我们可以首先将所有的作业按照ddl时间长短来排序,于是我们便可以得到最长的ddl,即所有日期中的最后一天,从这最后一天开始我们依次向前遍历,采用最大堆来记录作业,重写最大堆的比较函数,按照分数排列,当达到某一天时,我们便将ddl为这一天的任务加入到队列中,然后从中取出分数最高的来完成,由于我们是从后向前进行的,因此所有已经在堆里的作业都处于可以完成的转态,从中选出最高分的即可,最后堆里面还剩下的便是没有完成的任务,计算他们的分数即可,算法复杂度O(logn)。

由于我们安排任务是从最后一天选择分数最高的安排,假设一个最优解从后向前第k天的任务与我们的贪心解不同,由于我们的贪心策略,这一天的任务一定是除去已经被安排的任务以外可以完成的任务中分值最高的,又由于他是从后向前安排,因此对这k天之前任务安排的影响又是最小,因此我们的贪心解不会差,贪心成立。


总结:

对于贪心问题一定要找好贪心策略,同时又要采用合适的数据结构降低复杂度,从后向前遍历安排可以将ddl靠后的任务的安排对前序任务的影响降至最低,而采用堆结构则可以将每次选择的复杂度降低。


代码:

#include<queue>
#include<vector>
#include<stdio.h>
#include <algorithm> 

struct homework
{
	int score;
	int deadline;

	homework(int _score = 0,int _deadline = 0):score(_score),deadline(_deadline){}
	homework(const homework& t) :score(t.score), deadline(t.deadline) {}

	friend bool operator<(const homework& t1, const homework& t2)
	{
		return t1.score < t2.score;
	}
};

bool cmp(const homework& t1, const homework& t2)
{
	return t1.deadline < t2.deadline;
}

int main()
{
	int order;
	scanf_s("%d", &order);
	std::vector<homework>hw;
	while (order-- != 0)
	{
		int number;
		scanf_s("%d", &number);
		
		for (int i = 0; i < number; i++)
		{
			int ddl;
			scanf_s("%d", &ddl);
			hw.push_back(homework(0, ddl));
		}
		for (int i = 0; i < number; i++)
		{
			int score;
			scanf_s("%d", &score);
			hw[i].score = score;
		}
		
		sort(hw.begin(), hw.end(), cmp);

		std::priority_queue<homework>hp;

		int maxday = hw[number - 1].deadline;
		int nowday = maxday;
		int giveup = 0;

		while (nowday != 0)
		{
			for (int j = number-1; j >= 0; j--)
			{
				if (hw[j].deadline == nowday)
				{
					hp.push(hw[j]);
					number = j;
				}
				else 
				{
					break;
				}
			}

			while(!hp.empty())
			{
				homework temp = hp.top();
				if (temp.deadline >= nowday)
				{
					hp.pop();
					break;
				}
				else {
					giveup += temp.score;
					hp.pop();
				}
			}
			nowday--;
		}

		while (!hp.empty())
		{
			homework temp = hp.top();
			giveup += temp.score;
			hp.pop();
		}
		printf("%d\n", giveup);
		hw.clear();
	}
	

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值