(蒟蒻的總結並不能代表什么,只能說給以后的自己,防止后來忘記吧??可能有不對的地方,請指出)
沒有算法標簽
在學習OI好幾個月后回來再看這個總結,發現原本寫的二維的是錯的,特此更正2019.6.18(開心的金明二維的痛)
讓我們先附上一個01背包問題的基本題目:
給定 n 種物品和一個容量為 C 的背包,物品 i 的重量是 wi,其價值為 vi 。
問:應該如何選擇裝入背包的物品,使得裝入背包中的物品的總價值最大?
首先先是頭文件們以及定義們(還有輸入):
#inlcude<iostream> #include<cstdio> #include<algorithm> #include<string> #include<cstring> #incude<camth>//把我所記住的頭文件全寫上了(大家不要學我); using namespace std; int n,c;//定義物品數量及背包容量; int w[1000],v[1000];//定義數組w[i]和v[i]分別表示物品i的質量和價值(1000毫無意義); int f[1000][1000];//定義數組f[i][j]存放第i個時的當前最大值(亂說胡話); int main() { cin>>n>>c;//輸入n,c; for(int i=1;i<=n;i++) cin>>w[i]>>v[i];//輸入第1~n個物體的質量和價值 ;
接下來是時候發揮數組f的作用了。數組f存的是搜索(不是搜索)第i個物品時的最大價值。利用雙層循環,設數組f[i][j]為第i個物品時恰好質量為j(這里有一點貪心???)的最大值,顯然到f[i][j]時有兩種可能:
- 不選取第i個物品,則此時最大值為f[i-1][j];
- 選取第i個物品,則此時的最大值是f[i-1][j-w[i]]+v[i];(這里有必要解釋一下:因為選取第i個物品后恰好裝滿j的容積,那么在沒選取第i個物品時,恰好裝滿的是j-w[i]的容積。那么選取第i個物品之前的最大值就為f[i-1][j-w[i]],這時再加上第i個物品的價值,得到結果。
顯然我們要取這兩種中最大的一種:利用函數max,則有:
for(int i=1;i<=n;i++) for(int j=c;j>=0;j--) if(j-w[i]>=0)f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]);
else f[i][j]=f[i-1][j];
當循環結束時,我們就求得了最大總價值f[n][c];
這里附上表幫助理解:
附上完整代碼:
#inlcude<iostream> #include<cstdio> #include<algorithm> #include<string> #include<cstring> #incude<camth>//把我所記住的頭文件全寫上了(大家不要學我); using namespace std; int n,c;//定義物品數量及背包容量; int w[1000],v[1000];//定義數組w[i]和v[i]分別表示物品i的質量和價值(1000毫無意義); int f[1000][1000];//定義數組f[i][j]存放第i個時的當前最大值(亂說胡話); int main() { cin>>n>>c;//輸入n,c; for(int i=1;i<=n;i++) cin>>w[i]>>v[i];//輸入第1~n個物體的質量和價值 ; for(int i=1;i<=n;i++) for(int j=c;j>=0;j--){//從c開始倒敘搜索並j>=w[i]是為了防止出現負下標 if(j-w[i]>=0)f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]);
else f[i][j]=f[i-1][j]; cout<<f[n][c]<<endl;
顯然數組會很占空間,所以我們優化為一維數組(盡管沒太聽懂):
#inlcude<iostream> #include<cstdio> #include<algorithm> #include<string> #include<cstring> #incude<camth>//把我所記住的頭文件全寫上了(大家不要學我); using namespace std; int n,c;//定義物品數量及背包容量; int w[1000],v[1000];//定義數組w[i]和v[i]分別表示物品i的質量和價值(1000毫無意義); int f[1000];//定義數組f[i][j]存放第i個時的當前最大值(亂說胡話); int main() { cin>>n>>c;//輸入n,c; for(int i=1;i<=n;i++) cin>>w[i]>>v[i];//輸入第1~n個物體的質量和價值 ; for(int i=1;i<=n;i++) for(int j=c;j>=w[i];j--) f[j]=max(f[j],f[j-w[i]]+v[i]); cout<<f[c]<<endl;//希望沒輸錯……
end-