動態規划法-1.獨立任務最優調度問題C++實現


問題描述:

用2台處理機A和B處理n個作業。設第i個作業交給機器A處理時需要時間,若由機器B來處理,則需要時間。由於各作業的特點和機器的性能關系,很可能對於某些i,有,而對於某些j,j≠i,有。既不能將一個作業分開由2台機器處理,也沒有一台機器能同時處理2個作業。設計一個動態規划算法,使得這2台機器處理完這n個作業的時間最短(從任何一台機器開工到最后一台機器停工的總時間)。研究一個實例:(a1,a2,a3,a4,a5,a6)=(2,5,7,10,5,2);(b1,b2,b3,b4,b5,b6)=(3,8,4,11,3,4)。

算法設計:

對於給定的2台處理機A和B處理n個作業,找出一個最優調度方案,使2台機器處理完這n個作業的時間最短。

數據輸入:

由文件input.txt提供輸入數據。文件的第1行是1個正整數n, 表示要處理n個作業。接下來的2行中,每行有n個正整數,分別表示處理機A和B處理第i個作業需要的處理時間。

結果輸出:

將計算出的最短處理時間輸出到文件output.txt中。    

輸入文件示例

輸出文件示例

input.txt

output.txt

6

2 5 7 10 5 2

3 8 4 11 3 4

15

 

問題分析:

對於這個問題,我們可以考慮,當完成第k個任務時,有兩種可能:

    一是A處理機完成了第k個任務,那么B處理機完成k個任務的最短時間就與B處理機完成k-1個任務所需的最短時間是相同的

    二是B處理機完成了第k個任務,那么B處理機完成k個任務的最短時間就等於B處理機完成k-1個任務的最短時間加上B處理機完成第k個任務所需要的時間

設F[k][x]表示完成第k個任務時A耗費的時間為x的情況下B所花費的最短時間,其中0<=k <= n, 0<=x<= Σai,那么,狀態轉移方程為F[k][x]=minF[k−1][x−ak],F[k−1][x]+bk

處理好特殊情況(如x小於0時)開始填表即可。

最終的結果即是完成n個任務時A和B所需時間的較大值,即max(F[n][x], x).

算法實現:

 1 #include<iostream>
 2 #include<fstream>
 3 #include<string.h>
 4 using namespace std;
 5 
 6 int get_result(int a[],int b[],int n)
 7 {
 8     if(n==1)
 9         return min(a[0], b[0]);
10     int sum = 0,result = 10000;
11     for(int i=0;i<n;i++)
12     {
13         sum+=a[i];
14     }
15     int f[n][sum+1];
16     //初始化f(B處理用的時間)的各個元素為0 
17     memset(f, 0, sizeof(f));
18     
19     //初始化完成第一個任務時的情況
20     for(int x=0;x<a[0];x++)
21     {
22         f[0][x]=b[0];
23     } 
24     f[0][a[0]]=0;
25     
26     //動態規划過程
27     sum=a[0];
28     for(int k=1;k<n;k++)
29     {
30         sum+=a[k];
31         for(int x=0;x<=sum;x++)
32         {
33             if(x<a[k])
34             {
35                 f[k][x]=f[k-1][x]+b[k];
36             }
37             else
38             {
39                 f[k][x]=min(f[k-1][x-a[k]],f[k-1][x]+b[k]);
40             }
41             if(k==n-1)
42             {
43                 int val = max(x,f[k][x]);
44                 if(val<result)
45                     result = val;
46             }
47         }
48     }
49     return result;
50 }
51 
52 int main()
53 {
54     int n;
55     ifstream ifs;//創建文件流
56     ofstream ofs;
57     ifs.open("input.txt");
58     ofs.open("output.txt");
59     if(!ifs.is_open()||!ofs.is_open())
60     {
61         cout<<"open failed!"<<endl;
62         return 0;
63     }
64     ifs>>n;
65     int a[n+1],b[n+1];
66     for(int i=0;i<n;i++)
67     {
68         ifs>>a[i];
69     }
70     for(int i=0;i<n;i++)
71     {
72         ifs>>b[i];
73     }
74     int result=get_result(a,b,n);
75     cout<<result<<endl;
76     ofs<<result;
77     ifs.close();
78     ofs.close();
79     return 0;
80     
81 }

 

運行結果:

 

 

算法分析:

在get_result函數中,有兩個嵌套for循環,時間復雜度為O(n*sum),所以時間復雜度為O(n2)。

經驗歸納:

動態規划解題的一般思路:

1. 將原問題分解為子問題

把原問題分解為若干個子問題,子問題和原問題形式相同或類似,只不過規模變小了。子問題都解決,原問題即解決。

子問題的解一旦求出就會被保存,所以每個子問題只需求解一次。

2.確定狀態

在用動態規划解題時,我們往往將和子問題相關的各個變量的一組取值,稱之為一個“狀 態”。一個“狀態”對應於一個或多個子問題, 所謂某個“狀態”下的“值”,就是這個“狀 態”所對應的子問題的解。

所有“狀態”的集合,構成問題的“狀態空間”。“狀態空間”的大小,與用動態規划解決問題的時間復雜度直接相關。 在數字三角形的例子里,一共有N×(N+1)/2個數字,所以這個問題的狀態空間里一共就有N×(N+1)/2個狀態。

整個問題的時間復雜度是狀態數目乘以計算每個狀態所需時間。在數字三角形里每個“狀態”只需要經過一次,且在每個狀態上作計算所花的時間都是和N無關的常數。

3.確定一些初始狀態(邊界狀態)的值

4. 確定狀態轉移方程

定義出什么是“狀態”,以及在該“狀態”下的“值”后,就要找出不同的狀態之間如何遷移――即如何從一個或多個“值”已知的 “狀態”,求出另一個“狀態”的“值”(遞推型)。狀態的遷移可以用遞推公式表示,此遞推公式也可被稱作“狀態轉移方程”。

 


免責聲明!

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



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