兩類帶時限的作業排序問題


1   帶時限的作業排序問題

問題描述:

設有一個單機系統、無其它資源限制且每個作業運行相等時間,不妨假定每個作業運行 1 個單位時間。現有 n 個作業,每個作業都有一個截止期限di>0,di 為整數。如果作業能夠在截止期限之內完成,可獲得 pi>0 的收益。問題要求得到一種作業調度方案,該方案給出作業的一個子集和該作業子集的一種排列,使得若按照這種排列次序調度作業運行,該子集中的每個作業都能如期完成,並且能夠獲得最大收益。

輸入:

第一行輸入 n 的值,以下 n 行輸入作業號 i,收益 pi,截止期限 di。

輸出:

n 個作業的一個最優子集。

示例 

輸入:

      4

      1 100 2

      2 10 1

      3 15 2

      4 27 1

      1 4

輸出: 0 0 1 1

 

2   帶時限的作業排序問題II

問題描述:

帶時限的作業排序問題可描述為:設有 n 個作業和一台處理機,每個作業所需的處理時間、要求的時限和收益可用三元組(pi, di, ti),0<=i<n 表示,其中,作業 i 的所需時間為 ti,如果作業 i 能夠在時限 di 內完成,將可收益 pi,求使得總收益最大的作業子集 J。

輸入:

第一行輸入 n 的值;第二行輸入 pi;第三行輸入 di;第四行輸入 ti (i=0,…,n-1 且作業已經按時限非減次序排列)。

輸出:

xi(用固定長度 n-元組 xi 表示,xi=0 或 1,i=0,…,n-1)。

示例 

輸入:

      4

      5 3 6 10

      1 1 2 3

      1 1 1 2

輸出: 0 0 1 1

 

第1題

思路分析

這題的思路比較明顯,就是每次都選取作業收益最大的,並把它放在允許的最大的截止時間內完成,符合貪心算法的基本思想。將輸入的每個作業按收益從大到小進行排序,用一個數組vis表示某時刻是否已經有作業正在運行,vis[i]=1,表示時間i被占用 。然后從第1個作業開始往后搜索,將該作業安排到vis[d]時間運行,如果d已經有安排,將從d-1開始往前搜索,直到找到一個未被占用的時間點。如果找不到空時間點,則跳過此作業,繼續向后搜索直到所有作業都搜索完。

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <algorithm>
 4 #include <string.h>
 5 
 6 using namespace std;
 7 
 8 #define MAXN 1100
 9 
10 struct Node
11 {
12     int id; //編號 
13     int p;  //收益 
14     int d;  //截止期限 
15 }node[MAXN]; 
16 
17 int n;
18 int vis[MAXN];      //第i個單位時間是否有作業在運行 
19 vector<int> res;    //保存結果 
20 
21 bool cmp(Node a, Node b)
22 {
23     return a.p > b.p;
24 }
25 
26 int main()
27 {
28     scanf("%d", &n);
29     for(int i = 0; i < n; ++i)
30         scanf("%d%d%d", &node[i].id, &node[i].p, &node[i].d);
31     //按照收益從大到小排序 
32     sort(node, node+n, cmp);
33     memset(vis, 0, sizeof(vis));
34     
35     for(int i = 0; i < n; ++i)
36     {
37         // 如果到期時間沒有被占用,則直接占用到期時間;
38         // 否則,繼續往前找一個未被占用的時間 
39         if(!vis[node[i].d])
40         {
41             vis[node[i].d] = 1;
42             res.push_back(node[i].id); 
43         }
44         else
45         {
46             for(int j = node[i].d-1; j >= 1; --j)
47             {
48                 if(!vis[j])
49                 {
50                     res.push_back(node[i].id); 
51                     vis[j] = 1;
52                     break;
53                 }
54             }
55         }
56     } 
57     
58     for(int i = 0; i < res.size(); ++i)
59         printf("%d ", res[i]);
60 
61     return 0;
62 }

復雜度分析

從代碼來看,sort函數排序是O(nlogn)的時間復雜度,最差情況下,d >= n,且每組數據的截止期限都是d時,每次都要往前找一個空的時間點,此時需要找1+2+3+…+n次,所以耗費的時間為O(n2)。由於各個子塊不是嵌套的而是順序的,所以時間復雜度取最高的那個,所以整體來說時間復雜度是O(n2)。

對於空間復雜度,vis[]數組的大小由最大截止日期d決定。所以空間復雜度是O(d)。

 

第2題

這題和前面這題很相似,但其實解法有很大的差異。這題如果還是按前面那題的貪心思想去解題,是做不出來的,很難找到貪心算法中的最優度量標准。這題是一道比較難解決的問題,我在網上也沒找到解決方法。后來詢問一些算法比較厲害的同學之后,發現這題其實就是個0-1背包問題。

解題策略就是先選出最大的截止時間dmax,然后從1到dmax,進行0-1背包算法的操作。通過0-1背包的思路就可以找到最優解,這題相較於經典的0-1背包問題還是多了一些內容,那就是要記錄背包的路徑,最后輸出作業的子集的過程其實就是打印背包路徑的過程。

 1 #include <iostream>
 2 #include <stdio.h>
 3 
 4 using namespace std;
 5 
 6 int n;
 7 int p[110], d[110], t[110];
 8 int memo[1110];          //memo[i]表示截止期限為i時的最大收益 
 9 int path[1110][1110];   //記錄背包路徑 
10 
11 //遞歸打印背包路徑 
12 void printPath(int i, int j)
13 {
14     if(i < 0 || j < 0)
15         return;
16     
17     if(path[i][j] == 1)
18         printPath(i-1, j-t[i]); 
19     else
20         printPath(i-1, j);
21     
22     printf("%d ", path[i][j]);
23 
24 }
25 
26 int main()
27 {
28     scanf("%d", &n);
29     int dmax = -1;  //最大截止時間 
30     for(int i = 0; i < n; ++i)
31         scanf("%d", &p[i]);
32     for(int i = 0; i < n; ++i)
33         scanf("%d", &d[i]);
34     
35     //題中已經說明輸入按時限非減次序排列,所以d[n-1]就是最大的截止期限 
36     dmax = d[n-1];  
37     
38     for(int i = 0; i < n; ++i)
39         scanf("%d", &t[i]);
40         
41     for(int i = 0; i <= dmax; ++i)
42     {
43         if(i >= t[0])
44         {
45             memo[i] = p[0]; 
46             path[0][i] = 1;   //記錄路徑
47         }
48         else
49             memo[i] = 0;
50     } 
51     
52     for(int i = 1; i < n; ++i)
53     {
54         for(int j = dmax; j >= t[i]; --j)
55         {
56             if(memo[j] < p[i] + memo[j-t[i]])
57             {   //物品裝入背包,記錄路徑
58                 memo[j] = p[i] + memo[j-t[i]];
59                 path[i][j] = 1;     //記錄路徑 
60             }
61         }
62     }
63 
64     //遞歸打印背包路徑 
65     printPath(n-1, dmax);
66     
67     return 0;
68 }

復雜度分析

從代碼來看,這個程序運行的時間主要消耗在第一次的雙重循環中,外層循環的次數為n,內層循環次數為dmax,所以這個算法的平均時間復雜度為O(n*dmax)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM