1. 程式人生 > 實用技巧 >揹包問題(2)

揹包問題(2)

混合揹包

問題描述:

有n種物品,每件物品的重量為w[i],價值為v[i]。現有一個容量為C的揹包,問如何選取物品放入揹包,使得揹包內物品的總價值最大。其中有些物品只能取一次,有些物品可以取有限多次,有些物品可以取無限次。

問題分析:

這題其實就是0/1揹包完全揹包多重揹包三種問題混合起來。

對每種物體進行一次判斷,選擇對應的狀態轉移方程即可

這三種揹包問題的分析→揹包問題(1)

程式碼實現:

#include<iostream>
using namespace std;
#define MAX_CAPATICY 100
#define MAX_QUANTITY 100
int
w[MAX_QUANTITY+2];///物品重量 int v[MAX_QUANTITY+2];///物品價值 int m[MAX_QUANTITY+2];///第i種物品的件數,輸入0表示無限件 int dp[MAX_QUANTITY+2];///使用一維陣列 int c,n;///揹包容量和物品數量 int main() { while(cin>>c>>n){ for(int i=1;i<=n;++i){ cin>>w[i]>>v[i]>>m[i]; } for(int i=1
;i<=n;++i){ if(m[i]==0||m[i]*w[i]>c){///如果此物品總重量超過揹包容量 也當作完全揹包 for(int j=w[i];j<=c;++j){ dp[j]=max(dp[j],dp[j-w[i]]+v[i]); } } else{///多重揹包和0/1揹包 for(int j=c;j>=w[i];--j){ int
k=1,num=m[i]; while(k<=num){ dp[j]=max(dp[j],dp[j-k*w[i]]+k*v[i]); num-=k; k<<=1; } dp[j]=max(dp[j],dp[j-num*w[i]]+num*v[i]); } } } cout<<dp[c]; } return 0; }

二維揹包

問題描述:

對於每件物品,具有兩種不同的費用;選擇這件物品必須同時付出這兩種代價;對於每種代價都有一個可付出的最大值。問怎樣選擇物品可以得到最大的價值。設這兩種代價分別為代價1和代價2,第i件物品所需的兩種代價分別為a[i]和b[i]。兩種代價可付出的最大值分別為V和U。物品的價值為v[i]。

問題分析:

二維揹包和0/1揹包很像,只是加了一個費用條件

只需要多開一維陣列來儲存

參考0/1揹包問題 狀態轉移方程為:dp[j][k]=max(dp[j][k],dp[j-a[i]][k-b[i]]+v[i]

程式碼實現:

#include<iostream>
using namespace std;
#define MAX_CAPATICY 100
#define MAX_QUANTITY 100
int a[MAX_QUANTITY+2];///物品代價一
int b[MAX_QUANTITY+2];///物品代價二
int v[MAX_QUANTITY+2];///物品價值
int dp[MAX_QUANTITY+2][MAX_QUANTITY+2];///增加一維費用
int U,V,n;///揹包代價一最大值、代價二最大值和物品數量
int main()
{
    while(cin>>U>>V>>n){
        for(int i=1;i<=n;++i){
            cin>>a[i]>>b[i]>>v[i];
        }
        for(int i=1;i<=n;++i){
            for(int j=U;j>=a[i];--j){
                for(int k=V;k>=b[i];--k){
                    dp[j][k]=max(dp[j][k],dp[j-a[i]][k-b[i]]+v[i]);
                }
            }
        }
        cout<<dp[U][V]<<endl;
    }
    return 0;
}

分組揹包

問題描述:

有N件物品和一個最大承重為C的揹包,已知這N件物品的重量w[i]以及價值v[i],將這些物品劃分為K組,每組中的物品互相沖突,最多選一件,求解將哪些物品裝入揹包可使這些物品的費用綜合不超過揹包的容量,且價值總和最大。

問題分析:

類比0/1揹包,分組揹包多了分組

對於每件物品還是兩種選擇,選或是不選

先對第一組第一個進行判斷,選擇的話就對下一組第一個進行判斷,不選擇就對本組下一個進行判斷

程式碼實現:

#include<iostream>
using namespace std;
#define MAX_CAPATICY 100
#define MAX_QUANTITY 100
#include<vector>
int w[MAX_QUANTITY+2];///物品重量
int v[MAX_QUANTITY+2];///物品價值
vector<int> g[MAX_QUANTITY+2];///物品所在小組
int dp[MAX_QUANTITY+2];///使用一維陣列
int c,n,t;///揹包容量、物品數量和小組總數
int p;///物品所在小組
int main()
{
    while(cin>>c>>n>>t){
        for(int i=1;i<=n;++i){
            cin>>w[i]>>v[i]>>p;
            g[p].push_back(i);
        }
        for(int i=1;i<=t;++i){
            for(int j=c;j>=1;--j){
                for(int k=0;k<g[i].size();++k){///迴圈的順序千萬不能錯
                    if(j>=w[g[i][k]]){
                        dp[j]=max(dp[j],dp[j-w[g[i][k]]]+v[g[i][k]]);
                    }
                }
            }
        }
        cout<<dp[c]<<endl;
    }
    return 0;
}