HDUOJ 1789(贪心)

HDUOJ  1789(贪心)

Doing Homework again

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

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
  

 这道题的意思大概是:有较多功课要在指定的截止日期前(包括截止日期)完成。每门功课的分数和完成的截止日期不一样,若不能在规定时间完成,则扣除相应功课的分数,并且一天最多只能完成一门功课,问怎么安排才能使减去的分数最小(也可以理解为如何使得到的分数最多)。最后输出扣除的最小分数(不扣除便输出0,意思是扣除0分)


思路:

刚开始看到这道题一点思路也没有,大概想了4个多小时,才找到方法。

首先有两个方向:一是先按截止日期排序,再找相关解决办法。二是按分数大小进行排序,再找进一步的方法。

一:按时间排从小到大排序:   

                                                                            (刚开始认为这种方法得到的分数最大,实际上是错误的)

      截止日期           要交功课(多门)的分数            每个截止日期中选择分数最大的一门功课                   实际上 得到的分数最大的一组

            1                          2、3 、4                                                                 4                                                                                    6                        

            2                              4、5                                                                     5                                                                                    7                  

            3                           6、7、8                                                                 8                                                                                    8                

            4                               5、6                                                                    6                                                                                   6                   

            5                            1、1、1                                                                1                                                                                    1                   

显然我最开始的想法是不对的,可能别的高手还有别的方法,至少在时间这个方向上我实在想不出办法了(后来听同学说可以用队列来做)。于是我又开始转向到以分数为主线的方向:


二:   

  (之所以把分数从大到小排序并按此顺序判断并确定相应功课完成的日期,是为了确保分数较大的功课能够被完成,然后再考虑分数小的功课)


                   (已按从大到小排序)       *                                已按下面方法操作                                                    若不把分数大的功课放在截止日期完成,

  截止日期      相应功课的分数               *          完成日期        得到的分数最大的一组                        完成日期             得到的一组结果(仅以2       7为例验证)

        2                    7       由              *               2                        7                              *                1                                   7         

        4                    7                     *               4                        7                              *                4                                   7              

        1                    6                     *               1                        6                              *                3                                   5                 

        4                    5       小              *               3                        5                              *                5                                   3                 

        5                    3                     *               5                        3                              *                2                                   2                 

        2                    2                                   7                        1                              *                7                                   1      

        7                    1      判断            *     

     

                                                                                 

方法:分数从大到小排,若分数一样,按日期从小到大排。

把分数大的功课放在截止日期完成(若把该功课提前(新日期)完成,可能会把原本能在这个新日期完成的分数较大的功课挤下去,以上面的中间和右边的

两组数据为参考:若把2            7变为1         7,就是把这门分数为7而截止日期为2的功课放在第一天完成,则1          6被挤出,2          2,填补原来2           7 的位置  )若该日期已有功课要做,说明这个日期要做的功课的分数比现在这门功课的分数要高,因此现在这门功课要往前推一天,再次判断是否已有功课要做,若没有,则把这门功课放在这天完成,若仍有,则继续往前推。最后若没有找到空天(当前该天还没有功课要做),则不做该门功课,继续下一门功课的判断。(拿上面的左边的数据为例:4         7和4             5,因为4        7在4       5前面,所以当4         5出现时,第4天已有分数为7的功课要做,所以这门分数为5的功课要往前推一天,因为第3天暂时没有功课,所以这门5分的课要放在第3天完成。当2        2出现时,因为第1天和第2天都已有功课要做,所以这门功课不做,继续下一门功课的判断。)


My  solution:

/*2015.7.31*/

#include<stdio.h>
#include<stdlib.h>
struct stu 
 {
	int day;
	int score;
 }per[1100];
int cmp(const void *a,const void *b)
  {
	if((*(stu *)b).score!=(*(stu *)a).score)
	   return (*(stu *)b).score-(*(stu *)a).score;
	else
	    return (*(stu *)a).day-(*(stu *)b).day;
  }
  int c[1100];
int main()
{
	int i,j,n,m,sum,b,k;
	scanf("%d",&n);
	while(n--)
	{
		scanf("%d",&m);
		for(i=0;i<m;i++)
	    scanf("%d",&per[i].day);	
	   for(i=0;i<m;i++)
	    scanf("%d",&per[i].score);
	    qsort(per,m,sizeof(per[0]),cmp);
	    c[0]=per[0].day;
		i=1;/*用来记录已经安排好的功课数目(也可以理解为已安排好日期的天数)*/
		sum=0;/*记录扣除的总分数*/ 
	    for(j=1;j<m;j++)
		{
			b=per[j].day;
			for(k=0;k<i;k++)
			{
				if(b==c[k])
				{
					b--;/*该天已有功课要做,当前功课要往前推1天*/
					k=-1;/*往前推1天后,需要重新判断该天是否是空天,因此要从k=0开始判断,*/ 
				}             /* 因为循环最后要执行k++,所以这里令k=-1;*/ 
				if(b<=0)/*当前日期及其前面的日期都有安排,该门功课不做*/ 
				{
					sum+=per[j].score;
						break;
				}	
			}
			if(k==i)
			c[i++]=b;	
		}
		printf("%d\n",sum);
	}
	return 0;
}



/*2016.3.27*/

记得之前做过,当再次做时,又忘了,毫无头绪,于是又看了之前的题解,才想起来怎么做。汗汗汗汗!!!!!

#include<string.h>
#include<algorithm>
#include<stdio.h>
using namespace std;
struct  stu
{
	int score,time;
}s[1050];
int cmp(stu a,stu b)
{
	if(a.score!=b.score)
	return a.score>b.score;//分数从大到小排 
	else
	return a.time<b.time;//分数相同则按照截止时间来排,时间越紧急,越靠前排	
}
int mark[1010];
int main()
{
	int i,j,h,n,k,g,t,sum,fen;
	scanf("%d",&g);
	while(g--)
	{
		sum=0;//总分数 
		fen=0;//能得到的分数 
		memset(mark,0,sizeof(mark));
		scanf("%d",&n);
		for(i=1;i<=n;i++)
		{
			scanf("%d",&s[i].time);	
		} 
		for(i=1;i<=n;i++)
		{
			 scanf("%d",&s[i].score);
			 sum+=s[i].score;
		}
		sort(s+1,s+1+n,cmp);
		for(i=1;i<=n;i++)//n门功课 
		{
			t=s[i].time;
			if(mark[t]==0)
			{
				mark[t]=1;//标记该天已用 
				fen+=s[i].score; 
			}
			else
			{
				while(mark[t]&&t>0) //往前查找空闲时间来做该道题 ,但t>0 
				t--;
				if(t>0)
				{
					mark[t]=1;//标记该天已用 
					fen+=s[i].score;
				}	
			}
		}
		printf("%d\n",sum-fen);
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值