杭电oj1789:Doing Homework again(贪心)

Doing Homework again

题目链接

Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 21900 Accepted Submission(s): 12619

Problem Description

Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lot of homework to do. Every teacher gives him a deadline of handing in the homework. If Ignatius hands in the homework after the deadline, the teacher will reduce his score of the final test. And now we assume that doing everyone homework always takes one day. So Ignatius wants you to help him to arrange the order of doing homework to minimize the reduced score.

Input

The input contains several test cases. The first line of the input is a single integer T that is the number of test cases. T test cases follow.
Each test case start with a positive integer N(1<=N<=1000) which indicate the number of homework… Then 2 lines follow. The first line contains N integers that indicate the deadlines of the subjects, and the next line contains N integers that indicate the reduced scores.

Output

For each test case, you should output the smallest total reduced score, one line per test case.

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

这里详解实例(原文链接):

以第三个样例为例
4 7
2 6
4 5
3 4
1 3
4 2
6 1
假如我们先把4 7这份作业拿出来,回头看看,后边有很多事在 3 2 1天之内就要做完的啊,所以我们要考虑这样一个问题:这份作业我是先做了呢 还是等第四天最后做呢?
当然是第四天最后做了。把之前的时间让给截止时间早的作业啊。然后我们预计一下第一份作业(4 7)放在第四天做。然后我们拿出2 6这份作业,同理操作,将这份作业预定第二天去做,然后拿出4 5这份作业,这时候我们发现,第四天已经预定给了7学分的那份作业了,这份作业在第四天做的话不如刚刚预定的那样让7学分的在第四天做,这样能获得最大的学分,那么我这份 4 5的作业放在哪天做呢?这个时候我们要找到第三天的作业,相比较而言, 4 5这份作业比 3 4这份作业在第三天做获得的学分更多更划算一些。然后我们预定了这份作业在第三天去做。那么3 4这份作业又要去哪里做呢,看看第二天吧,第二天也预定了,而且第二天做的6学分的作业,比这个4学分的划算,那看看第一天吧,第一天没有预定,细心的我想去看看第一天就必须交的那份作业价值多少学分呢?找到一看 3学分,比我这个4学分低,当然要做4学分的作业啦,划算一些。这个时候把第一天预定做3 4这份作业。然后我们拿出1 3这份作业,诶,第一天我们有预定的作业了,但是第一天预定的作业获得的学分比这份作业获得的学分多,合适,我宁愿这份作业扔掉任其扣分了。然后是4 2 这份作业,也是无奈的扣掉了分,然后是6 1这份作业,第六天没有预定,然后预定第六天做这份作业,一整个整理作业的过程也就结束了。我一共扣掉了5个学分,也同时找到了最优解。

所以思路如下:根据贪心的思想,优先考虑扣分多的作业,先处理它们。具体做法,将作业以扣分多少降序排序。从扣分最多的作业开始,将它安排在它的截止日期那一天完成,若那天已经被占用了,则往前移一天,如果前面的天数都被占用了,则这个作业只能放弃,必须要被扣分.

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int maxn = 1010;

struct STR
{
	int deadline;
	int source;
	bool operator <(const STR &obj) const
	{
		return source > obj.source;
	}
}str[maxn];

int visit[maxn];
//标记第i天是否已经被安排做作业
//visit[i] = 0:没有安排
//visit[i] = 1:已经安排

int main()
{
	//freopen("in.txt", "r", stdin); 
	int T;
	cin>>T;
	while(T--)
	{
		int n;
		cin>>n;
		for(int i=0;i<n;i++)
			cin>>str[i].deadline;
		
		for(int i=0;i<n;i++)	
			cin>>str[i].source;
		
		memset(visit, 0, sizeof(visit));
		sort(str, str+n);
		
		int ans = 0; 
		for(int i=0;i<n;i++)
		{
			int deadline = str[i].deadline;
			if(!visit[deadline])
			{//做作业 
				visit[deadline] = 1;
				continue;	
			}
			while(deadline > 0 && visit[deadline])
				deadline--;
			if(deadline == 0)//扣分
				ans += str[i].source;
			else//提前做作业 
				visit[deadline] = 1;
		}
		cout<<ans<<endl;
	}
	return 0;
}

上述代码还可以做一些精简,如下:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int maxn = 1010;

struct STR
{
	int deadline;
	int source;
	bool operator <(const STR &obj) const
	{
		return source > obj.source;
	}
}str[maxn];

int visit[maxn];

int main()
{
	//freopen("in.txt", "r", stdin); 
	int T;
	cin>>T;
	while(T--)
	{
		int n;
		cin>>n;
		for(int i=0;i<n;i++)
			cin>>str[i].deadline;
		
		for(int i=0;i<n;i++)	
			cin>>str[i].source;
		
		memset(visit, 0, sizeof(visit));
		sort(str, str+n);
		
		int ans = 0; 
		/*******************变动如下**********************/
		for(int i=0;i<n;i++)//先把分数大的做了 
		{
			int deadline = str[i].deadline;
			while(deadline > 0 && visit[deadline])
				deadline--;
			if(deadline == 0)//扣分
				ans += str[i].source;
			visit[deadline] = 1;//做作业
		}
		/************************************************/
		cout<<ans<<endl;
	}
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值