動態規劃之背包問題,動態規劃背包
背包問題
有N件物品和一個容量為V的背包,第i件物品的體積是c[i],價值是w[i]。求解將哪些物品裝入背包可使價值總和最大。
狀態轉移方程:
f[i][v]=max(f[i−1][v],f[i−1][v−c[i]]+w[i])
這個方程非常重要,基本上所有跟背包相關的問題的方程都是由它衍生出來的
偽碼如下:
for i=1..N for v=V..0 f[v]=max{f[v],f[v-c[i]]+w[i]};
如果不放第i件物品,那麼問題就轉化為”前i−1件物品放入容量為v的背包中”,價值為f[i−1][v];
如果放第i件物品,那麼問題就轉化為”前i−1件物品放入剩下的容量為v−c[i]的背包中”,此時能獲得的最大價值就是f[i−1][v−c[i]]再加上通過放入第i件物品獲得的價值w[i]。
例題
Description
辰辰是個天資聰穎的孩子,他的夢想是成為世界上最偉大的醫師。為此,他想拜附近最有威望的醫師為師。醫師為了判斷他的資質,給他出了一個難題。醫師把他帶到一個到處都是草藥的山洞裡對他說:“孩子,這個山洞裡有一些不同的草藥,采每一株都需要一些時間,每一株也有它自身的價值。我會給你一段時間,在這段時間裡,你可以採到一些草藥。如果你是一個聰明的孩子,你應該可以讓採到的草藥的總價值最大。”
如果你是辰辰,你能完成這個任務嗎?
Input
輸入的第一行有兩個整數T(1 <= T <= 1000)和M(1 <= M <= 100),用一個空格隔開,T代表總共能夠用來採藥的時間,M代表山洞裡的草藥的數目。接下來的M行每行包括兩個在1到100之間(包括1和100)的整數,分別表示採摘某株草藥的時間和這株草藥的價值。
Output
輸出包括一行,這一行只包含一個整數,表示在規定的時間內,可以採到的草藥的最大總價值。
Sample Input
70 371 10069 11 2
Sample Output
3
解題代碼1
#include <iostream>using namespace std;int main(){ int T, M; cin>>T>>M; int c[101] = {0}; int w[101] = {0}; for (int i = 1; i <= M; i++) { cin>>w[i]>>c[i]; } int **f = new int*[M + 1]; for (int i = 0; i <= M; i++) { f[i] = new int[T + 1]; } //草藥數目為0 for (int i = 0; i <= M; i++) { f[i][0] = 0; } //採藥時間為0 for (int i = 0; i <= T; i++) { f[0][i] = 0; } int i, j; for (i = 1; i <= M; i++) { for (j = 1; j <= T; j++) { if (j >= w[i]) { f[i][j] = max(f[i - 1][j], f[i - 1][j - w[i]] + c[i]); } else { f[i][j] = f[i - 1][j]; } } } cout<<f[i-1][j-1]<<endl; //cout<<f[M][T]<<endl; for (int i = 0; i <= M; i++) { delete [] f[i]; } delete [] f; return 0;}
解題代碼2
#include <iostream>using namespace std;int main(){ int T, M; cin>>T>>M; int c[101] = {0}; int w[101] = {0}; for (int i = 1; i <= M; i++) { cin>>w[i]>>c[i]; } int f[1001][101] = {0}; for (int i = 1; i <= M; i++) { for (int j = 1; j <= T; j++) { if (j >= w[i]) { f[i][j] = max(f[i - 1][j], f[i - 1][j - w[i]] + c[i]); } else { f[i][j] = f[i - 1][j]; } } } cout<<f[M][T]<<endl; return 0;}
代碼2多耗費一些空間,但是代碼可以簡潔很多。
解題代碼3
可以選擇使用一維數組來解決該問題,但是值得注意的是,記憶體迴圈的順序必須是V..0,即:
for i=1..N for v=V..0 f[v]=max{f[v],f[v-c[i]]+w[i]};
如果內層迴圈為0..V,則實際的狀態方程為:
f[i][v]=max(f[i−1][v],f[i][v−c[i]]+w[i])
#include <iostream>using namespace std;int main(){ int T, M; cin>>T>>M; int c[101] = {0}; int w[101] = {0}; for (int i = 1; i <= M; i++) { cin>>w[i]>>c[i]; } int f[101] = {0}; for (int i = 1; i <= M; i++) { for (int j = T; j >= 1; j--) { if (j >= w[i]) { f[j] = max(f[j], f[j - w[i]] + c[i]); } } } cout<<f[T]<<endl; return 0;}