hdu 1789 Doing Homework again 贪心算法

Doing Homework again

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

 

 

Author

lcy

 

 

Source

2007省赛集训队练习赛(10_以此感谢DOOMIII

本人代码:

/*贪心算法*/

#include<stdio.h>

#include<string.h>

#define max 1005

struct he

{

         int time;

         int score;

};

bool f[max];

int main()

{

         int t,n,i,min,j;

         he student[max],temp;

         scanf("%d",&t);

         while(t--)

         {

                   scanf("%d",&n);

                   for(i=0;i<n;i++)

                            scanf("%d",&student[i].time);

                   for(i=0;i<n;i++)

                            scanf("%d",&student[i].score);

                   min=0;

                   memset(f,0,sizeof(f));

                   for(i=0;i<n;i++)

                            for(j=i+1;j<n;j++)

                            {

                                     if(student[j].score>student[i].score)

                                     { temp=student[j];student[j]=student[i];student[i]=temp; }

                                     else if(student[j].score==student[i].score && student[j].time<student[i].time)

                                     { temp=student[j];student[j]=student[i];student[i]=temp; }

                            }

                   for(i=0;i<n;i++)

                   {

                            for(j=student[i].time;j>0;j--)

                            {

                                     if(f[j]==false)

                                     {

                                               f[j]=true;

                                               break;

                                     }

                            }

                            if(j==0)

                            min+=student[i].score;

                   }

                   printf("%d/n",min);

         }

         return 0;

}

之后又查了网上代码,和我的其实一样,不过他讲得比我详细:

/*
    又是贪心水题,我也想做有水平的题目无奈水平太菜。
    此题大致思路,既然要计算最少扣多少分,就眼前利益
    考虑必然要先把超过最后时间扣分最多的作业先安排了
    如果扣分一样多的话,那必然要把时间比较紧的先安排
    .所以先按扣分的高低,由高向低排序,如果两门课
    扣分相同就按他们的结束时间有低向高排序!然后选择即可!
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 1002
int flag[MAX];
typedef struct
node
{
   
int
deadline;
   
int
score;
}limit;
limit c[MAX];
int cmp(const void *a,const void
*b)
{
   
if
((*(limit *)a).score!=(*(limit *)b).score)
    {
       
return (*(limit *)b).score>(*(limit *)a).score?1:-1
;
    }
   
else

    {
       
return (*(limit *)a).deadline>(*(limit *)b).deadline?1:-1;
    }
}
int
main()
{
   
int
t,n,i,sum,j;
   
//freopen("in.txt","r",stdin);//用到文件输入

    scanf(
"%d",&t);
   
while
(t--)
    {
        sum=
0
;
        memset(flag,
0,sizeof
(flag));
        scanf(
"%d"
,&n);
       
for(i=0
;i<n;i++)
        {
            scanf(
"%d"
,&c[i].deadline);
        }
       
for(i=0
;i<n;i++)
        {
            scanf(
"%d"
,&c[i].score);
        }
        qsort(c,n,
sizeof(c[0
]),cmp);
       
for(i=0
;i<n;i++)
        {
           
for(j=c[i].deadline;j>0;j--)//从最后的期限开始考虑前几天有没有被安排

            {                          
//如果一直到结束都没有空余时间,最后只能扣分
               
if(0==flag[j])
                {
                    flag[j]=
1
;
                   
break
;
                }
            }
           
if(0
==j)
            {
                sum+=c[i].score;   
            }
        }
        printf(
"%d/n"
,sum);                   
    }
   
return 0
;
}

 

 

贪心算法 HDU1789 Doing Homework again

题目大意:

IgnatiusN项作业要完成。每项作业都有限期,如果不在限期内完成作业,期末考就会被扣相应的分数。给出测试数据T表示测试数,每个测试以N开始(N0时结束),接下来一行有N个数据,分别是作业的限期,再有一行也有N个数据,分别是若不完成次作业会在期末时被扣的分数。求出他最佳的作业顺序后被扣的最小的分数。(每个作业费时一天)。

解题思路:

求被扣分数最少。这是一道贪心算法。于是第一个想法就是:使用一个结构体保存每门作业的限制时间deadline和被扣的分数reduce

对限制时间排序,限制越大的要越先完成,若托限制时间一样,则把被扣分数大的排在前面,保证被扣分数达的要先完成。这就保证了完成的作业数做多。但是这样排序后,产生了一个问题,完成的作业数做多,被扣的分数不一定是最小,例如:

输入:7

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

如果只按上述排序从头去到尾则结果是7。这是因为在上面的数组中,可以选择完成(4 5),放弃(1 3)。这样才是最小的结果。

所以做法是:设一个mark数组,标记能够完成的。然后对排序后的结构体数据进行for循环,遇到

Ifday<deadline(即现在的时间不超过限制时间)则表示这个作业可以完成,)

{所以day++,同时mark[i]要标记这个作业可以完成。}

Elseday>=deadline,则证明这个作业放在这里做没办法完成的。)

{

考虑在前面标记过的可完成的作业,是否有某个作业的reduce比目前的ruduce小。

If(如果有)

{则证明,可以选择完成当前的这个作业,而不完成前面reduce比当前小的作业,所以两个作业的reduce交换。}

   Else(如果没有)

          {则什么都不操作,进入下一次循环}

}

 

仅供参考。

Code

#include<stdio.h>

#include<algorithm>

using namespace std;

struct HomeWork

{

    int deadline;

    int reduce;

}hw[1005];

bool mark[1005];

int t;int n;

int search(HomeWork a[],int x,int len)

{

    int i,pl=-1,min=x;

    for(i=0;i<len;i++)

        if(mark[i]==true&&a[i].reduce<min)

        {

            min=a[i].reduce;

            pl=i;

        }

        return pl;

}

bool cmp(HomeWork a ,HomeWork b)

{

    if(a.deadline!=b.deadline)

        return a.deadline<b.deadline;

    else

        return a.reduce>b.reduce;

}

int main()

{

    scanf("%d",&t);

    while(t--)

    {

        memset(mark,0,sizeof(mark));

        memset(hw,0,sizeof(hw));

        int i;

        scanf("%d",&n);

        for(i=0;i<n;i++)

            scanf("%d",&hw[i].deadline);

        for(i=0;i<n;i++)

            scanf("%d",&hw[i].reduce);

        sort(hw,hw+n,cmp);

  

        int day=0,reduced=0,tmp;

        for(i=0;i<n;i++)

        {

            if(day<hw[i].deadline)

            {

                day++;mark[i]=true;

            }

            else

            {

                int ex=search(hw,hw[i].reduce,i);

                if(ex!=-1)

                {

                    tmp=hw[ex].reduce;

                    hw[ex].reduce=hw[i].reduce;

                    hw[i].reduce=tmp;

                  

                }

          

                    reduced+=hw[i].reduce;

 

            }

        }

      

        printf("%d/n",reduced);

      

    }

    return 0;

}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值