c++——DDl的恐惧

题意

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

Hint

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

思路

从最后一个DDL开始,向前走,每向前走一天就加上当天为ddl的所有作业,然后解决一个分值最大的作业,最后剩下的都是相对小分值得作业,这样才能导致最后剩下的作业里面扣的分最少。

代码

#include <iostream>
#include <cstdio>
#include <unordered_map>
#include <queue>
#include <algorithm>
using namespace std;
unordered_map<int, int> mp;
struct m
{//存储ddl 和 分数
	int ddl;
	int score;
	bool operator < (const m& b) const
	{//排序按 扣的分排 最大的优先
		if (score != b.score)  return score < b.score;
		return ddl > b.ddl;
	}
};
vector<m> a(5000);
bool cmp(const m& a, const m& b)
{//先按时间排序 最大ddl排到前面
	if (a.ddl != b.ddl) return a.ddl > b.ddl;
	return a.score > b.score;
}
int main(int argc, char** argv)
{
	int T;
	scanf("%d", &T);
	int n;
	for (int t = 0; t < T; t++)
	{
		priority_queue<m> b;//优先队列  按分值大小排序
		scanf("%d", &n);
		for (int i = 0; i < n; i++)
		{
			scanf("%d", &a[i].ddl);
			mp[a[i].ddl]++;    //记录每个ddl下有多少个作业
		}
		for (int i = 0; i < n; i++)
		{
			scanf("%d", &a[i].score);
		}
		sort(a.begin(), a.begin()+n, cmp);   //按ddl排序
		int alen = 0;
		for (int i = a[0].ddl; i > 0; i--)
		{//i从最晚得一个ddl开始 向前走
			if (mp[i]!=0)
			{//将以当天为ddl得所有作业加入优先队列
				for (int j = 0; j < mp[i]; j++)
				{
					b.push(a[alen]);
					alen++;   
				}
			}
			if (!b.empty())
			{
				b.pop();  //队列中有作业得话 就每天删除一个最大得
			}
		}
		int sum = 0;
		while(!b.empty())
		{
			sum+=b.top().score;   //计算剩下的没做完得作业分数
			b.pop();
		}
		cout << sum << endl;
		mp.clear();
	}
	return 0;
}

反思及总结

这道题考验贪心算法;
刚开始没有想到用优先队列来做堆,使用了STL里面的make_heap方法,底层为vector容器实现,发现一个小问题,就是c++ STL里面的堆实现删除并不是真正的删除了堆顶元素,而是将元素放在了vector的尾部,导致每次都做同一份作业。后面改用优先队列存储,同样的思想,一边过。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值