一、用動態規劃方法手工求解下面的問題:
某工廠調查瞭解市場情況,估計在今後四個月內,市場對其產品的需求量如下表所示。
時期(月) | 需要量(產品單位) |
---|---|
1 | 2 |
2 | 3 |
3 | 2 |
4 | 4 |
已知:對每個月來講,生產一批產品的固定成本費為3 (千元),若不生產,則為零。每生產單位產品的成本費為1 (千元)。同時,在任何一個月內,生產能力所允許的最大生產批量為不超過6 個單位。又知每單位產品的庫存費用為每月0.5 (千元),同時要求在第一個月開始之初, 及在第四個月末,均無產品庫存。
問:在滿足上述條件下,該廠應如何安排各個時期的生產與庫存,使所花的總成本費用最低?
要求:寫出各種變數、狀態轉移方程、遞推關係式、和詳細計算步驟。
該題既可以順推也可以逆推,但逆推的手工計算量較小。因此這裡用逆推的方式求解。
-
變數描述:設\(n\) 為總月份,\(w_i\) 代表第\(i\)個月的需求量,\(u_i\) 代表第\(i\)個月的產量,生產固定成本\(c_1=3\) ,生產單位產品成本費\(c_2=1\) ,單位產品的庫存費\(c_3=0.5\) ,單月最大生產量\(max_p=6\)
-
狀態轉移方程:
記\(s_i\)為第i個月的庫存,則\(s_{i+1}=s_i + u_i - w_i\),且\(s_i \geq 0\),\(0 \leq u_i \leq max_p\)
\(v_i\)為第i個月的花費,則\(v_i = c_3s_i+\begin{cases}c_2u_i+c_1&,&u_i>0\\0&,&u_i=0\end{cases}\)
設\(f_i(s_i)\)為第i個月後,庫存為\(s_i\)的最小成本,則
\[f_i(s_i)=min_{u_i}\{{v_i + f_{i + 1}(s_{i+1})}\} \]最終所求為\(f_1(0)\)
-
遞推關係式:
\[\begin{cases} f_n(0)=0\\ f_i(s_j)=min_{u_i}\{v_i+f_{i+1}(s_k)\} \end{cases} \] -
計算步驟:
由題知,所求\(n = 4; w = \{2,3,2,4\}\),所以有\(u_4=s_5-s_4+w_4=4-s_4\),即\(0 \leq s_4 \leq 4\),
\[f_4(s_4)=min_{u_4}\{v_4+f_{5}(0)\}=min_{u_4}\{0.5 * s_4+\begin{cases}1 * u_4+3&,&u_4>0\\0&,&u_4=0\end{cases}\} \implies \begin{cases} f_4(0)=7&,&u_4=4\\ f_4(1)=6.5&,&u_4=3\\ f_4(2)=6&,&u_4=2\\ f_4(3)=5.5&,&u_4=1\\ f_4(4)=2&,&u_4=0\\ \end{cases} \]所以有\(u_3=s_4-s_3+w_3\),即\(0 \leq s_3 \leq 6\)
\[f_3(s_3)=min_{u_3}\{v_3+f_{4}(s_4)\}=min_{u_3}\{0.5 * s_3+\begin{cases}1 * u_3+3&,&u_3>0\\0&,&u_3=0\end{cases}\} \implies \begin{cases} f_3(0)=11&,&u_3=6\\ f_3(1)=10.5&,&u_3=6\\ f_3(2)=8&,&u_3=0\\ f_3(3)=8&,&u_3=0\\ f_3(4)=8&,&u_3=0\\ f_3(5)=8&,&u_3=0\\ f_3(6)=5&,&u_3=0\\ \end{cases} \]所以有\(u_2=s_3-s_2+w_2\),即\(0 \leq s_2 \leq 9\)
\[f_2(s_2)=min_{u_2}\{v_2+f_{3}(s_3)\}=min_{u_2}\{0.5 * s_2+\begin{cases}1 * u_2+3&,&u_2>0\\0&,&u_2=0\end{cases}\} \implies \begin{cases} f_2(0)=16&,&u_2=5\\ f_2(1)=15.5&,&u_2=4\\ f_2(2)=15&,&u_2=3\\ f_2(3)=12.5&,&u_2=0\\ f_2(4)=12.5&,&u_2=0\\ f_2(5)=10.5&,&u_2=0\\ f_2(6)=11&,&u_2=0\\ f_2(7)=11.5&,&u_2=0\\ f_2(8)=12&,&u_2=0\\ f_2(9)=9.5&,&u_2=0\\ \end{cases} \]而\(s_1 = 0\),\(u_1=s_2 - s_1 + w_1\),
\[f_1(s_1)=min_{u_1}\{v_1+f_{2}(s_2)\}=min_{u_1}\{0.5s_1+\begin{cases}1 * u_1+3&,&u_1>0\\0&,&u_1=0\end{cases}\} \implies f_1(0)=20.5,u_1=5 \]故\(u=[5,0,6,0]\),\(s = [0,3,0,4]\),即4個月分別生產5、0、6、0單位產品,各月庫存量分別為0、3、0、4,總成本最低為\(f_1(0)=20.5\)
二、用動態規劃方法程式設計求解下面的問題:
某推銷員要從城市\(v_1\) 出發,訪問其它城市\(v_2,v_3,…,v_6\) 各一次且僅一次,最後返回\(v_1\)。D為各城市間的距離矩陣。
問:該推銷員應如何選擇路線,才能使總的行程最短?
要求:寫出遞推關係式、虛擬碼和程式相關說明,並分析時間複雜性。 (請遵守第一節課提出的有關 assignment 的要求)
-
變數描述:記城市數量\(n=6\),城市編號為\(0,1,2,\dots,n-1\),距離矩陣為\(D\);
-
狀態轉移方程:設\(f_{i,S}\)代表推銷員走到第i個城市,已經訪問過的城市集合為S,則
\[f_{i,S}=min\{f_{j,S-\{i\}}+D_{j,i}\} \] -
遞推關係式:初始時S為空,\(f_{i,S}=0\)
\[\begin{cases} f_{i,S}=0\\ f_{i,S}=min\{f_{j,S-\{i\}}+D_{j,i}\} \end{cases} \] -
虛擬碼:
func TSP(n, D){ // Input: n城市數量,D為距離矩陣下標從0開始 // Output: 一個數,代表從v1=0出發,最後回到v1的最小距離 初始化f為INF 將v1新增進集合S,此時f[i][S]=0 從{v1}開始列舉集合S的狀態 列舉第i個城市是否在集合內,如果在 列舉不在集合內的第j個城市 將j加入集合S記為S‘,此時花費為f[i][S] + D[i][j] 記f[j][S']=min{f[j][S'], f[i][S] + D[i][j]} 則得到f[i][S]為從0出發,最後集合狀態為S的最小 最後加上從最後經過的城市返回v1的距離,輸出答案 }
-
時間複雜度:\(O(n^2*2^n)\)
-
附程式程式碼:
#include<iostream> #include<cstring> using namespace std; #define INF 0x3f3f3f3f const int n = 6; const int D[6][6]={ {0,10,20,30,40,50}, {12,0,18,30,25,21}, {23,19,0,5,10,15}, {34,32,4,0,8,16}, {45,27,11,10,0,18}, {56,22,16,20,12,0} }; int f[10][1024]; int main() { memset(f, INF, sizeof(f)); f[0][1] = 0; int tot = (1 << n) - 1; for (int s = 1; s <= tot; s++) { for (int i = 0; i < n; i++) { if ((s >> i & 1 == 0) || (f[i][s] == INF)) continue; for (int j = 0; j < n; j++) if ((s >> j & 1) == 0) f[j][s | 1 << j] = min(f[j][s | 1 << j], f[i][s] + D[i][j]); } } int ans = INF; for (int i = 0; i < n; i++) if (f[i][tot] < INF) ans = min(ans, f[i][tot] + D[i][0]); cout << ans << endl; }