動態規劃(dynamic programming)是經過組合子問題的解而解決整個問題的。分治算法是指將問題劃分爲一些獨立的子問題,遞歸地求解各子問題,而後合併子問題的解而獲得原問題的解。動態規劃適用於子問題不是獨立的狀況,也就是各子問題包含公共的子子問題。在這種狀況下,若用分治法則會作許多沒必要要的工做,即重複地求解公共的子子問題。動態規劃對每一個子子問題只求解一次,將結果保存在一張表中,從而避免每次遇到各個子問題時從新計算答案。ios
動態規劃一般應用於最優化問題。此類問題可能有不少種可行解,每一個解有一個值,咱們但願找出一個具備最優(最大或最小)值的解,稱這樣的解爲該問題的一個最優解(而不是肯定的最優解),由於可能存在多個取最優解的值。算法
動態規劃算法的設計可分爲以下4個步驟:測試
(1)描述最優解的結構。優化
(2)遞歸定義最優解的值。spa
(3)按自底向上的方式計算最優解的值。設計
(4)由計算出的結果構造一個最優解。3d
裝配線調度code
Colonel汽車公司在有兩條裝配線的工廠內生產汽車。一個汽車底盤在進入每一條裝配線後,在一些裝配站中會在底盤上安裝部件,而後,完成的汽車在裝配線的末端離開。每一條裝配線上有n個裝配站,編號爲j=1,2,…,n。將裝配線i(i爲1或2)的第j個裝配站表示爲。裝配線1的第j個站()和裝配線2的第j個站()執行相同的功能。然而,這些裝配站是在不一樣的時間建造的,而且採用了不一樣的技術,所以,每一個站上所需的時間是不一樣的,即便在兩天不一樣裝配線相同位置的裝配站上也是這樣。把在裝配站上所需的裝配時間記爲。底盤進入裝配線i的進入時間爲ei,裝配完的汽車離開裝配線i的離開時間爲xi。blog
正常狀況下,一旦一個底盤進入一條裝配線後,它只會通過該條裝配線。在相同的裝配線中,從一個裝配站到下一個裝配站所花的時間能夠忽略。偶爾會來一個特別急的訂單,客戶要求儘量快地製造這些汽車。對這些加急的訂單,底盤仍然依序通過n個裝配站,但工廠經理能夠將部分完成的汽車在任何裝配站上從一條裝配線移到另外一條裝配線上。把已經經過裝配站的一個底盤從裝配線i移走所花的時間爲,其中i=1,2,j=1,2,…,n-1(由於在第n個裝配站後,裝配已經完成)。問題是要肯定在裝配線1內選擇哪些站以及在裝配線2內選擇哪些站,以使汽車經過工廠的總時間最小。遞歸
解題報告:
步驟1:描述最優解的特徵。
對於裝配線調度問題,一個問題(找出經過裝配站的最快路線)最優解包含了子問題(找出經過或的最快路線)的一個最優解。稱這個性質爲最優子結構,這是是否能夠應用動態規劃方法的標誌之一。能夠利用子問題的最優解來構造原問題的一個最優解。
步驟2:一個遞歸的解。
利用子問題的最優解來遞歸定義一個最優解的值。選擇在兩條裝配線上經過裝配站j的最快路線問題做爲子問題,j=1,2,…,n。
令表示一個底盤從起點到裝配站的最快可能時間,爲底盤經過工廠的全部路線的最快時間,則,其中,。進一步得出:
步驟3:計算最快時間。
整個過程花費時間。
步驟4:構造經過工廠的最快路線。
參考代碼以下:
1 #include <iostream> 2 using namespace std; 3 4 typedef struct 5 { 6 int **a; 7 int **t; 8 int *e; 9 int *x; 10 int n; 11 }LineCondition; 12 13 void FastestWay(const LineCondition *line, int **&l, int **&f, int &ftotal, int &lend) 14 { 15 int n = line->n; 16 17 f[0][0] = line->e[0] + line->a[0][0]; 18 f[1][0] = line->e[1] + line->a[1][0]; 19 20 for (int i = 1; i < n; ++i) 21 { 22 if (f[0][i - 1] + line->a[0][i] <= f[1][i - 1] + line->t[1][i - 1] + line->a[0][i]) 23 { 24 f[0][i] = f[0][i - 1] + line->a[0][i]; 25 l[0][i] = 1; 26 } 27 else 28 { 29 f[0][i] = f[1][i - 1] + line->t[1][i - 1] + line->a[0][i]; 30 l[0][i] = 2; 31 } 32 33 if (f[1][i - 1] + line->a[1][i] <= f[0][i - 1] + line->t[0][i - 1] + line->a[1][i]) 34 { 35 f[1][i] = f[1][i - 1] + line->a[1][i]; 36 l[1][i] = 2; 37 } 38 else 39 { 40 f[1][i] = f[0][i - 1] + line->t[0][i - 1] + line->a[1][i]; 41 l[1][i] = 1; 42 } 43 } 44 45 if (f[0][n - 1] + line->x[0] <= f[1][n - 1] + line->x[1]) 46 { 47 ftotal = f[0][n - 1] + line->x[0]; 48 lend = 1; 49 } 50 else 51 { 52 ftotal = f[1][n - 1] + line->x[1]; 53 lend = 2; 54 } 55 } 56 57 void PrintStations(int **l, int lend, int n) 58 { 59 int *a = new int[n]; 60 int i = lend - 1; 61 int m = n; 62 a[--m] = i + 1; 63 64 for (int j = n - 1; j > 0; --j) 65 { 66 i = l[i][j] - 1; 67 a[--m] = i + 1; 68 } 69 70 for (int i = 0; i < n; ++i) 71 { 72 cout << "line " << a[i] << ", station " << i + 1 << endl; 73 } 74 75 delete [] a; 76 } 77 78 79 int main(void) 80 { 81 LineCondition line; 82 83 cout << "請輸入裝配站數目n:"; 84 cin >> line.n; 85 86 line.a = new int *[2]; 87 for (int i = 0; i < 2; ++i) 88 { 89 line.a[i] = new int [line.n]; 90 } 91 for (int i = 0; i < 2; ++i) 92 { 93 cout << "請輸入裝配線" << i + 1 << "上每一個裝配站耗費時間a[i][j]:"; 94 for (int j = 0; j < line.n; ++j) 95 { 96 cin >> line.a[i][j]; 97 } 98 } 99 100 line.t = new int *[2]; 101 for (int i = 0; i < 2; ++i) 102 { 103 line.t[i] = new int [line.n - 1]; 104 } 105 for (int i = 0; i < 2; ++i) 106 { 107 cout << "請輸入裝配線t[" << i << "][j]:"; 108 for (int j = 0; j < line.n - 1; ++j) 109 { 110 cin >> line.t[i][j]; 111 } 112 } 113 114 line.e = new int [2]; 115 cout << "請輸入e1,e2:"; 116 cin >> line.e[0] >> line.e[1]; 117 118 line.x = new int [2]; 119 cout << "請輸入x1,x2:"; 120 cin >> line.x[0] >> line.x[1]; 121 122 int **l = new int *[2]; 123 int **f = new int *[2]; 124 for (int i = 0; i < 2; ++i) 125 { 126 l[i] = new int [line.n]; 127 f[i] = new int [line.n]; 128 } 129 130 int lend, ftotal; 131 FastestWay(&line, l, f, ftotal, lend); 132 PrintStations(l, lend, line.n); 133 134 return 0; 135 }
按照以下圖片輸入相關數據:
測試結果以下: