一、實驗內容
運用動態規划算法解決矩陣連乘問題(或流水作業調度、或背包問題)
使用動態規划算法解決0-1背包問題。
二、所用算法基本思想及復雜度分析
1.算法基本思想
動態規划基本思想是一種在數學、計算機科學和經濟學中經常使用的,通過把原問題分解為相對簡單的子問題的方式求解復雜問題的方法,但是經分解得到的子問題往往不是互相獨立的,不同子問題的數目常常只有多項式量級。
2.問題分析及算法設計
問題分析:
(1) 有n個物品,它們有各自的體積和價值,現有給定容量的背包,如何讓背包里裝入的物品具有最大的價值總和。
(2) 根據動態規划解題的步驟(首先進行問題抽象化、建立模型、尋找約束條件、判斷是否滿足最優性原理、找大問題與小問題的遞推關系式、填表、尋找解組成)。
(3) 建立模型,即求max(V1X1+V2X2+…+VnXn)。
(4) 尋找約束條件,W1X1+W2X2+…+WnXn<capacity。
(5) 得到遞推關系式,然后填表。
(6) 找出0-1背包問題的最優解以及解組成,然后編寫代碼實現。
算法設計:
(1) 通過填寫表把所有已經解決的子問題答案紀錄下來,在新問題里需要用到的子問題可以直接提取,避免了重復計算,從而節約了時間,所以在問題滿足最優性原理之后,用動態規划解決問題的核心就在於填表,表填寫完畢,最優解也就找到。
(2) 特例:
- 算法復雜度分析
01背包問題屬於NP問題之一,每個物品有選和不選兩種策略,若采用暴力搜索算法,其時間復雜度為O(2n),而采用動態規划的方式,則可以將時間復雜度從O(2n)降到O(n^2),通過自底向上逐層遞推可以求得最優解。
三、源程序核心代碼及注釋(截圖)
四、運行結果
五、調試和運行程序過程中產生的問題及解決方法,實驗總結(5行以上)
剛剛學習動態規划時調試運行,感覺數據變換的順序太復雜,然后去百度,看各優秀博主的講解和特例,然后再結合自己的代碼,簡單的畫了草圖,然后跟據自己所畫的草圖,結合表中的數據來一個一個的調試,這使得調試的過程變得簡單易懂。這次動態規划的實驗,讓我對動態規划有了初步的認識,也明白了最優化原理是動態規划的基礎,它主要是不論前面決策如何,都對后各階段的決策序列必須構成最優策略。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
const int N = 401;
const int M = 1501;
int V[N][M];
int max(int a, int b)
{
if (a > b)
return a;
else
return b;
}
int dpKnapSack(int n, int c, int w[], int v[])
{
int i, j;
for (j = 0; j <= c; j++)
{
V[0][j] = 0;//當沒裝物品時,價值統一為0
}
for (i = 1; i <= n; i++)//物體編號
{
for (j = 1; j <= c; j++)//背包容量
{
if (j < w[i])//沒裝第i件物品
V[i][j] = V[i - 1][j];
else//裝第i件物品
V[i][j] = max(V[i - 1][j], V[i - 1][j - w[i]] + v[i]);
}
}
return V[n][c];
}
int main()
{
int w[N], v[N];
int n, c, i;
while (scanf("%d%d", &n, &c) != EOF) {
for (i = 1; i <= n; i++)
{
cin >> w[i];
}
for (i = 1; i <= n; i++)
{
cin >> v[i];
}
cout << dpKnapSack(n, c, w, v) << endl;
}
return 0;
}