動態規劃0—1揹包問題
阿新 • • 發佈:2019-02-06
動態規劃0-1揹包問題
Ø 問題描述: 給定n種物品和一揹包。物品i的重量是wi,其價值為vi,揹包的容量為C。問應如何選擇裝入揹包的物品,使得裝 入揹包中物品的總價值最大? Ø 對於一種物品,要麼裝入揹包,要麼不裝。所以對於一種物品的裝入狀態可以取0和1.我們設物品i的裝入狀態為xi,xi∈ (0,1),此問題稱為0-11揹包問題。 過程分析資料:物品個數n=5,物品重量w[n]={0,2,2,6,5,4},物品價值V[n]={0,6,3,5,4,6},
(第0位,置為0,不參與計算,只是便於與後面的下標進行統一,無特別用處,也可不這麼處理。)總重量c=10.
Ø揹包的最大容量為10,那麼在設定陣列m大小時,可以設行列值為6和11,那麼,對於m(i,j)就表示可選物品為i…n揹包容量為j(總重量)時揹包中所放物品的最大價值。
下面寫點,我對動態規劃淺薄的理解,希望看到這篇文章的同學們,能更容易理解這個演算法思想。
首先,要明白這個演算法的核心,我建議首先要會暴力求最值的演算法,就是用搜索去求最值的演算法,不管是用dfs,還是bfs,都可以,首先你要建立一個狀態的概念,搜尋中就會有這個概念,明白從一個狀態到一個狀態怎麼搜尋,怎麼求。動態規劃的實質就是,將問題化為求解子問題,前一個子問題最值問題求解了,如果你找到子問題與當前問題的關係,那麼當前問題就解決了,是一個迭代的過程。另外,將搜尋進行記憶化,其實也是一種dp的思想,我覺得首先你得了解記憶化搜尋的思想,才能入得了動態規劃的門,明白啦這個思想之後,後面的東西你慢慢就領悟啦,不然老是說dp,看了一遍,覺得懂了,下次又忘啦,其實就是用空間換時間的一種搜尋而已,很簡單的思想。
下面是自己寫的原始碼:
#include<stdio.h> #include<stdlib.h> #include<iostream> #include<queue> #include<climits> #include<cstring> using namespace std; const int c = 10; //揹包的容量 const int w[] = {0,2,2,6,5,4};//物品的重量,其中0號位置不使用 。 const int v[] = {0,6,3,5,4,6};//物品對應的待加,0號位置置為空。 const int n = sizeof(w)/sizeof(w[0]) - 1 ; //n為物品的個數 int x[n+1]; void package0_1(int m[][11],const int w[],const int v[],const int n)//n代表物品的個數 { //採用從底到頂的順序來設定m[i][j]的值 //首先放w[n] for(int j = 0; j <= c; j++) if(j < w[n]) m[n][j] = 0; //j小於w[n],所對應的值設為0,否則就為可以放置 else m[n][j] = v[n]; //對剩下的n-1個物品進行放置。 int i; for(i = n-1; i >= 1; i--) for(int j = 0; j <= c; j++) if(j < w[i]) m[i][j] = m[i+1][j];//如果j < w[i]則,當前位置就不能放置,它等於上一個位置的值。 //否則,就比較到底是放置之後的值大,還是不放置的值大,選擇其中較大者。 else m[i][j] = m[i+1][j] > m[i+1][j-w[i]] + v[i]? m[i+1][j] : m[i+1][j-w[i]] + v[i]; } void answer(int m[][11],const int n) { int j = c; int i; for(i = 1; i <= n-1; i++) if(m[i][j] == m[i+1][j]) x[i] = 0; else { x[i] = 1; j = j - w[i]; } x[n] = m[i][j] ? 1 : 0; } int main() { int m[6][11]={0}; package0_1(m,w,v,n); for(int i = 0; i <= 5; i++) { for(int j = 0; j <= 10; j++) printf("%2d ",m[i][j]); cout << endl; } answer(m,n); cout << "The best answer is:\n"; for(int i = 1; i <= 5; i++) cout << x[i] << " "; system("pause"); return 0; }