【總結】01背包問題


(蒟蒻的總結並不能代表什么,只能說給以后的自己,防止后來忘記吧??可能有不對的地方,請指出)

沒有算法標簽

在學習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]時有兩種可能:

  1. 不選取第i個物品,則此時最大值為f[i-1][j];
  2. 選取第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-


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM