0-1 背包問題(動(dòng)態(tài)規(guī)劃)

題目描述
給定n種物品和一個(gè)背包,物品i的重量是Wi,其價(jià)值為Vi,問如何選擇裝入背包的物品,使得裝入背包的物品的總價(jià)值最大?

在選擇裝入背包的物品時(shí),對(duì)每種物品i只能有兩種選擇,裝入或者不裝入,不能裝入多次,也不能部分裝入。

輸入
第一行輸入物品的個(gè)數(shù)n。

第二行輸入物品的重量序列w。(中間有空格)

第三行輸入物品的價(jià)值序列v。(中間有空格)

第四行輸入背包容量c。

輸出
第一行輸出裝入背包的物品。(用0和1表示,中間無空格)

第二行輸出最大價(jià)值。

樣例輸入
3
3 4 5
4 5 6
10
樣例輸出
011
11
背包問題是動(dòng)態(tài)規(guī)劃的最為基礎(chǔ)的問題。初看背包問題,便知道肯定不是用貪心做法,直接選擇用動(dòng)態(tài)規(guī)劃,那就是先分析問題,我們可以得到一個(gè)最優(yōu)子結(jié)構(gòu),如果選n個(gè)物品,容量為c,得到一個(gè)最大值,那顯然,選n-1個(gè)物品,容量為c 或者 c-第n個(gè)物品的重量的最大值是之前的一個(gè)最大值的子結(jié)構(gòu)。因此我們不但能得到最優(yōu)子結(jié)構(gòu),甚至還能知道轉(zhuǎn)移方程該如何構(gòu)造。dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]),這里的i是一直選到第i個(gè)物品,j是容量,那我們最終的答案是什么呢?如果知道這個(gè),就明白了這個(gè)遞推表達(dá)式的含義了,詳情看代碼。
本題還需要得到一個(gè)最優(yōu)解,一般來說動(dòng)態(tài)規(guī)劃如果要求得最優(yōu)解的話,是通過之前我們存放的那個(gè)dp表,來找規(guī)律的,然后通過回溯法來找到最優(yōu)解。我已將dp表打印了出來,規(guī)律希望大家能找到,代碼如下。

#include<iostream>
#define max(x,y) (x)>(y)?(x):(y)
using namespace std;
int f(int **dp,int n,int c,int *w,int *s){
    if(dp[n][c]==0){
        s[n]=0;
        return 0;
    }
    
    if(dp[n][c]!=dp[n-1][c]){
        s[n]=1;
        f(dp,n-1,c-w[n],w,s);
    }
    else{
        s[n]=0;
        f(dp,n-1,c,w,s);
    }
} 
void fun(int n,int *w,int *v,int c,int *s){
    int **dp=new int *[n+1];
    for (int i=0;i<=n;i++){
        dp[i]=new int [c+1];
    } 
    
    for(int i=0;i<=c;i++){
        dp[0][i]=0;
    }
    for(int i=1;i<=n;i++){
        for(int j=0;j<=c;j++){
            if(j>=w[i])
                dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
            else
                dp[i][j]=dp[i-1][j];
        }
    }
    for(int i=n;i>=1;i--){
        for(int j=1;j<=c;j++)
            cout<<dp[i][j]<<" ";
        cout<<'\n';
    } 
    f(dp,n,c,w,s);//構(gòu)造最優(yōu)解
    for(int i=1;i<=n;i++){
        cout<<s[i];
    }
    cout<<'\n';
    cout<<"背包內(nèi)最大價(jià)值為"<<dp[n][c];
    delete []dp;
}
int main(){
    int n;
    cout<<"請(qǐng)輸入n"<<endl;
    cin>>n;
    int w[n];
    int v[n];
    cout<<"請(qǐng)分別輸入物品重量"<<endl; 
    for(int i=1;i<=n;i++){
        cin>>w[i];
    }
    cout<<"請(qǐng)分別輸入物品價(jià)值"<<endl;
    for(int i=1;i<=n;i++){
        cin>>v[i];
    }
    int *s=new int [n+1];//存放最優(yōu)解 
    int c;
    cout<<"請(qǐng)輸入背包容量c"<<endl;
    cin>>c;
    fun(n,w,v,c,s);
} 

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容