Doing Homework again HDU - 1789

Doing Homework again HDU - 1789

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

题意:给定作业的截止日期,和每个作业的分值,如果在截止日期内没完成改作业,将会被扣分。每天能完成一个作业,现在要求最小被扣分的值。

分析:这题一眼就是贪心算法,那么我们改如何去贪心呢,首先我们都会想到,既然要扣分最少,又要在期限内,那么,我们就先按照日期从小到大排序,先截止的先做,然后如果截止日期一样的,我们按照扣分从大到小,扣分多的先做完,也就是说优先选择扣分多的做。 但是这样贪心是不完整的,贪心问题要做到局部最优到整体最优的状态。

下面我们就用样例3来分析

未排序前:
1 4 6 4 2 4 3
3 2 1 7 6 5 4
按照上面的排序法则:
结果是:
1 2 3 4 4 4 6
3 6 4 7 5 2 1

我们发现一个很大的问题,如果光这样排序,当第五天的时候,我们是要被罚5分的,但是如果我们把第一天和第5天的交换一下,由于第一天是扣3分的,第5天是扣5分,一交换就能少扣2分。说明我们还需要更改决策。。

怎么办呢?

我们需要在结构体里增加一个变量flag ,flag=0表示不做,flag=1表示已做

day变量就是时间,每次++;

如果 当前点的截止日期>=day ,说明这一天可以做的,我们就把flag=1,day++

当 当前点的截止日期>day 当前节点不能做,这里是关键,此时我们需要减掉分数了,但是我不甘心,因为如果前面做过的作业,有分值比我低,那我还是想要它的分值的,这样我就能少扣,找到前面做过的最小值,然后交换flag,意思就是,前面那个最小值的作业我不做了,做当前的。如果找不到最小值,那就乖乖做吧,flag=1.

遍历完一遍后,flag=0的都是被扣分的。

AC代码:

#include <bits/stdc++.h>
using namespace std;
int const N=1005;
int t,n; 
struct Node{
	int time;
	int zhi;
	int flag;//0表示没做,1表示做了 
}a[N];
bool cmp(Node x,Node y)
{//首先按照时间短的排序,相同时间,优先选择罚分多的 
	if(x.time!=y.time)return x.time<y.time;
	else return x.zhi>y.zhi;
}
void init()
{
	for(int i=0;i<n;i++)
	{
		a[i].flag=0;
		a[i].time=0;
		a[i].zhi=0;
	}
}
int main()
{
	while(~scanf("%d",&t))
	{
		while(t--)
		{
			init();
			scanf("%d",&n);
			for(int i=0;i<n;i++)scanf("%d",&a[i].time);
			for(int i=0;i<n;i++)scanf("%d",&a[i].zhi);
			sort(a,a+n,cmp);
			int day=1;
			for(int i=0;i<n;i++)
			{
				if(a[i].time>=day)
				{
					day++;
					a[i].flag=1;
				}
				else
				{
					int pos=-1;
					int minn=a[i].zhi;
					for(int j=0;j<i;j++)
					{
						if(a[j].zhi<minn&&a[j].flag==1)
						{
							minn=a[j].zhi;
							pos=j;
						}
					}
					if(pos!=-1)
					{
						a[pos].flag=0;
						a[i].flag=1;
					}
				}
			}
//			for(int i=0;i<n;i++)printf("%d%c",a[i].time,i==n-1?'\n':' ');
//			for(int i=0;i<n;i++)printf("%d%c",a[i].zhi,i==n-1?'\n':' ');
//			for(int i=0;i<n;i++)printf("%d%c",a[i].flag,i==n-1?'\n':' ');
			int sum=0;
			for(int i=0;i<n;i++)
			{
				if(a[i].flag==0)sum+=a[i].zhi;
			}
			printf("%d\n",sum);
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值