CSP_Week4 Problem A DDL困境(貪心板子c++)

題目概述

原題敘述

ZJM 有 n 個作業,每個作業都有自己的 DDL,如果 ZJM 沒有在 DDL 前做完這個作業,那麼老師會扣掉這個作業的全部平時分。
所以 ZJM 想知道如何安排做作業的順序,才能儘可能少扣一點分。

INPUT

輸入包含T個測試用例。輸入的第一行是單個整數T,爲測試用例的數量。
每個測試用例以一個正整數N開頭(1<=N<=1000),表示作業的數量。
然後兩行。第一行包含N個整數,表示DDL,下一行包含N個整數,表示扣的分。

OUTPUT

對於每個測試用例,您應該輸出最小的總降低分數,每個測試用例一行。

輸入樣例

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

輸出樣例

0
3
5

備註

上方有三組樣例。
對於第一組樣例,有三個作業它們的DDL均爲第三天,ZJM每天做一個正好在DDL前全部做完,所以沒有扣分,輸出0。
對於第二組樣例,有三個作業,它們的DDL分別爲第一天,第三天、第一天。ZJM在第一天做了第一個作業,第二天做了第二個作業,共扣了3分,輸出3。

題目重述

有n個DDL,他們都有一個固定的結束時間和分值,只要在結束時間之前完成就可以獲得相應的分數。但與傳統的分值貪心問題不同的是,完成每個DDL需要的時間是相同的都爲1天。
由於輸入比較複雜進行一下說明方便後面的解題:
第一行:要處理的數據樣例個數
第二行:第一組樣例的數據個數
第三行:每個DDL的結束的時間
第四行:每個DDL的分值
後面部分就是第二行到第四行的循環(樣例說明見題目備註)

解題思路

題目比較明顯就是一道貪心算法的題目。但是要注意的有下面幾個點:
1、DDL在結束的那一天完成是可以獲得積分的。
2、完成每個DDL的花費是相同的(一天),但是收穫並不相同(不同積分)。
3、題目要求的是求出最少的扣分,也可以理解爲得到最多的分數。
根據上面的三個點,我們就可以開始建立貪心策略了,由於是等花費,不用再考慮時間段帶來的問題,只需要儘可能安排分數較高的DDL。爲了保證在安排時對其他DDL的影響最小,我們採用倒敘安排從最後一天開始安排能夠安排的DDL中分值最高的。
有趣的是,雖然題面簡單,該題目通過改變數據量的大小也能一定程度上加大難度:
可以從下面兩個角度思考問題:
如果數據區域是1e3即1000,選擇什麼實現方法?
如果數據區域增加到1e6 ,前面的方法還會奏效麼?又該使用什麼算法呢?
很明顯1e3的數據範圍,O(n^2)的時間複雜度是完全可以接受的。我們可以暴力的進行求解,也就是首先按照分值排序,然後在每次的選擇時都遍歷一遍DDL,選擇當前可以安排且沒有被安排過的,且分值最大的進行安排。這種算法雖然笨重,但是數據較少且想不到好的優化方法時,不失爲一種備用的方案。
接下來是Problem 2,數據量提升到了1e6,經過簡單計算可以知道O(n^2)的時間複雜度一定會爆掉。在不重構的算法的前提下,我們可以在前面算法的基礎上進行優化。經過分析可知,Problem 1的算法浪費了大量的時間複雜度在選DDL的過程中。但實際上,我們的實質需求只是選出最大分數的DDL。在選最大值的算法優化方面,堆是一種簡便且高效的方法,引入大根堆即可將時間複雜度將至O(logn),完成題目需求。

題目源碼

這裏我們只列出了Problem 1的解法,Problem 2等待你的補充。

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
struct ddl
{
    int time;
    int score;
    int flag;
    bool operator<(ddl & a)
    {
        return score>a.score;
    }
}a[1010];
int main()
{
    int number=0;
    scanf("%d",&number);
    for(int i=0;i<number;i++)
    {
        int all_score=0;
        int end_time=0;
        int choose_score=0; 
        int group=0;
        scanf("%d",&group);
        for(int j=0;j<group;j++)
        {
            a[j].flag=0;
            a[j].score=0;
            a[j].time=0;
            scanf("%d",&a[j].time);
            if(a[j].time>end_time)
            end_time=a[j].time;
        }
        for(int j=0;j<group;j++)
        {
            scanf("%d",&a[j].score);
            all_score+=a[j].score;
        }
        sort(a,a+group);
        for(int k=end_time;k>=1;k--)
        {
            for(int q=0;q<group;q++)
            {
                if(a[q].flag==0 && a[q].time>=k)
                {
                    a[q].flag=1;
                    choose_score+=a[q].score;
                    break;
                }
            }
        }
        printf("%d\n",all_score-choose_score);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章