單位時間的調度問題 | 貪心

更新一下今天 “計算理論與算法設計” 期末考試的三道編程題,沒有測試用例的題真是太藍受了。分享一下我考試時的思路,最後也給出了我編寫的自測用例。僅供參考,如有錯誤還請指出~


02

成績 15 開啓時間 2020年06月24日 星期三 15:10
折扣 0.8 折扣時間 2020年06月24日 星期三 18:30
允許遲交 關閉時間 2020年06月24日 星期三 18:30

題目描述:

現有一個機器要處理n項任務,每項任務都可以在一個單位時間內完成。每項任務有截止時間(d1, d2,,…, dn),和超過截止時間內未完成的懲罰因子(w1, w2,,…, wn)。求所有任務排列中最小的懲罰因子和。例如若有3項任務,其截止時間爲(2,2,2),懲罰因子爲(6,7,8)。排列123,132,213,231,312,321的懲罰因子和爲分別是8,7,8,6,7,6。可見6是所有任務排列中懲罰因子最小和爲6。

輸入格式:

共三行,第一行爲一個整數n(0<n<=10000),第二行是n個正整數d1, d2,,…, dn(保證在int內),第三行是n個正整數w1, w2,,…, wn(保證在int內)。

輸出格式:

一行一個數,即最小懲罰因子和。

  測試輸入 期待的輸出 時間限制 內存限制 額外進程
測試用例 1  
  1. 3↵
  2. 2 2 2↵
  3. 6 7 8↵
 
  1. 6↵
1秒 64M 0

       本題顯然是貪心實現,具體怎麼貪心呢!大概的思路就是:優先考慮懲罰更重的任務,在考慮每一個任務的時候安排它在最靠近dll的時間完成。可以證明此題滿足貪心選擇性質,如此貪心策略也是正確的。


1、數據預處理

       首先將任務用一個結構體表示,包含任務的 ddl 和懲罰 weight。然後創建一個任務的 thing[ ] 數組,並且對數組以 weight 爲關鍵字降序排序。

struct node {
    int deadLine;  //ddl
    int weight;  //懲罰
} thing[MAXN];

bool cmp(struct node x, struct node y) {
    if (x.weight == y.weight)  //當懲罰一樣時
        return x.deadLine < y.deadLine;  //優先ddl在前面的
    else
        return x.weight > y.weight;  //優先懲罰更重的
}

       對輸入的處理和各種數組的初始化我放到一個 Init() 函數中實現。爲了方便安排時間段,定義一個時間槽:用數組 done[ ] 來表示。若 done[ i ] = true,則表示第 i 個單位時間段是空閒的。所以應該初始化 done 全爲 true,每次分配一個時間就賦值爲 false 以避免衝突。

void Init() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &thing[i].deadLine);
    for (int i = 1; i <= n; i++)
        scanf("%d", &thing[i].weight);
    for(int i = 0;i <= n; i++)
        done[i] = true;
}

2、貪心實現

      按照我們排序後的順序(即優先考慮懲罰更重的任務),依次考慮每一個任務,安排它在最靠近 dll 的時間完成。如果找不到,就無法完成。

/* 爲任務t尋找合適的時間
 * 找不到則返回false */
bool Done(struct node t) {
    //找到最接近ddl的空閒時間段
    for(int i = t.deadLine; i >= 1; i--)
        if(done[i]) {
            done[i] = false;
            return true;
        }
    //找不到則返回假
    return false;
}

int Calc() {
    sort(thing + 1, thing + n + 1, cmp);  //對任務以懲罰爲關鍵字排序

    int ans= 0;
    for(int i = 1; i <= n; i++) {
        if(!Done(thing[i]))  //對於找不到合適時間的任務
            ans += thing[i].weight;  //加入懲罰
    }
    return ans;
}


下面附上完整代碼測試用例

#include <cstdio>
#include <algorithm>
#define MAXN 10050
using namespace std;

int n;
bool done[MAXN];   //第i個時間段是否有空

struct node {
    int deadLine;  //ddl
    int weight;  //懲罰
} thing[MAXN];

bool cmp(struct node x, struct node y) {
    if (x.weight == y.weight)  //當懲罰一樣時
        return x.deadLine < y.deadLine;  //優先ddl在前面的
    else
        return x.weight > y.weight;  //優先懲罰更重的
}

void Init() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &thing[i].deadLine);
    for (int i = 1; i <= n; i++)
        scanf("%d", &thing[i].weight);
    for(int i = 0;i <= n; i++)
        done[i] = true;
}

/* 爲任務t尋找合適的時間
 * 找不到則返回false */
bool Done(struct node t) {
    //找到最接近ddl的空閒時間段
    for(int i = t.deadLine; i >= 1; i--)
        if(done[i]) {
            done[i] = false;
            return true;
        }
    //找不到則返回假
    return false;
}

int Calc() {
    sort(thing + 1, thing + n + 1, cmp);  //對任務以懲罰爲關鍵字排序

    int ans= 0;
    for(int i = 1; i <= n; i++) {
        if(!Done(thing[i]))  //對於找不到合適時間的任務
            ans += thing[i].weight;  //加入懲罰
    }
    return ans;
}

int main() {
    Init();
    printf("%d\n", Calc());
}

測試用例:

4
1 1 3 4
7 8 9 10
輸出:7


4
2 2 2 1
16 7 8 2
輸出:9


5
5 5 2 2  3
12 3 1 2 9
輸出:0


6
3 3 3 4 4 4
7 8 9 12 1 3
輸出:4


8
1 1 1 2 2 2 3 3
1 2 3 1 3 3 5 4
輸出:10


3
2 2 2

6 7 8
輸出:6


4
1 1 2 3
1 2 7 9
輸出:1


6
1 3 4 4 6 1
21 2 20 9 25 15
輸出:15


6
6 1 4 1 4 3
0 4 5 10 16 23
輸出:4


7
4 2 4 3 1 4 6
70 60 50 40 30 20 10
輸出:50



end 

歡迎關注個人公衆號 雞翅編程 ”,這裏是認真且乖巧的碼農一枚。

---- 做最乖巧的博客er,做最紮實的程序員 ----

旨在用心寫好每一篇文章,平常會把筆記彙總成推送更新~

在這裏插入圖片描述

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章