1. 程式人生 > >杭電OJ 1789(貪心)

杭電OJ 1789(貪心)

Doing Homework again

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


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 掛科問題永遠都是搞ACM的兄弟們的痛苦...一邊想全身心的投入題目當中,還得算計好時間複習,熬夜搞突擊...傷不起....

題目大意:

給出n個作業,同時表示有n天.第一行輸入表示截止時間(deadline 簡稱dl)第二行表示如果逾期,要扣除對應的學分

讀了題目馬上就能知道這是一道貪心題,但是思路呢?馬上想到的是最短的時間完成最多的分數啦~.

問題關鍵詞還是鎖定在了學分的身上,我們輸出的是最小扣除學分,那麼我們就要在有限的時間裡邊完成最多的高分作業,這個時候我們首先想到了排序.

學分從高到底排序:

struct homework
{
    int dl,s;
}a[1001];
int cmp(homework a,homework b)
{

    if(a.s==b.s)
    {
        return a.dl<b.dl;
    }
    return a.s>b.s;
}
然後呢,我們這裡邊看題乾的第三組樣例:


我們擁有七天的時間,缺有3個4天的重複作業。我們光排了學分的順序是遠遠不夠的,假如這個例子排序之後的順序如下:

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個學分,也同時找到了最優解。

那麼我們這裡要處理的問題是,如何保證先預定的一定是學分高的合算的作業呢?我們剛剛有談到排序的操作,我們排序的時候就解決了這個問題,另外的問題就是預定的問題,我們這裡用一個vis[]陣列就能輕鬆搞定。

所以這個題目的解答思路就是:給每一份作業都預定上做那份作業的時間,預定天數的同時要保證這份作業一定是要價值最高,方案最好的。我們這裡就應用了排序的操作,然後就是預定天數的順序,我們要儘量把作業放在截止的當天去做,能把大量的時間讓給重複的作業和之前截止的作業。

這裡貼上核心程式碼:

       sort(a,a+n,cmp);//排序
       int output=0;
       for(int i=0;i<n;i++)
       {
           int j=a[i].dl;//令j表示截止天數
           while(j)//預定日期
           {
               if(vis[j]==0)//如果當前日期(作業截止當天)沒有預定,並且我保證了截止當天做這份作業是不虧的前提下(不愧的前提是排序)
               {
                   vis[j]=1;//我們就預定了這一天
                   break;
               }
               j--;//否則就向前找預定的日期
           }
           if(j==0)
           {
               output+=a[i].s;//如果預定不到日期,就只能放棄了
           }
       }

然後是完整的AC程式碼:
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
struct homework
{
    int dl,s;
}a[1001];
int vis[1001];
int cmp(homework a,homework b)
{

    if(a.s==b.s)
    {
        return a.dl<b.dl;
    }
    return a.s>b.s;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(vis,0,sizeof(vis));
       int n;
       scanf("%d",&n);
       for(int i=0;i<n;i++)
       {
           scanf("%d",&a[i].dl);
       }
       for(int i=0;i<n;i++)
       {
           scanf("%d",&a[i].s);
       }
       sort(a,a+n,cmp);
       int output=0;
       for(int i=0;i<n;i++)
       {
           int j=a[i].dl;
           while(j)
           {
               if(vis[j]==0)
               {
                   vis[j]=1;
                   break;
               }
               j--;
           }
           if(j==0)
           {
               output+=a[i].s;
           }
       }
       printf("%d\n",output);
    }
}