1. 程式人生 > 其它 >揹包九講(8)

揹包九講(8)

揹包九講(8)

揹包問題求方案數

有 N 件物品和一個容量是 V的揹包。每件物品只能使用一次。

第 ii 件物品的體積是 vi,價值是 wi。

求解將哪些物品裝入揹包,可使這些物品的總體積不超過揹包容量,且總價值最大。

輸出 最優選法的方案數。注意答案可能很大,請輸出答案模 109+7 的結果。

輸入格式

第一行兩個整數,N,V,用空格隔開,分別表示物品數量和揹包容積。

接下來有 N 行,每行兩個整數 vi,wi,用空格隔開,分別表示第 i件物品的體積和價值。

輸出格式

輸出一個整數,表示 方案數 模 109+7 的結果。

資料範圍

0<N,V≤1000
0<vi,wi≤1000

輸入樣例

4 5
1 2
2 4
3 4
4 6

輸出樣例:

2

01揹包問題的變種,由於是記錄01揹包的方案數,所以在開一個數組g來記錄體積為N時的方案數。

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 1010;
//01揹包環境下 
int f[N];//記錄體積為N時最大價值
int g[N];//記錄體積為N時的方案數
int n,m;

const int mod=1e9+7;
const int INF=10000000;
int main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++)f[i]=-INF;//f[N]初始化時,f[0]為0,其他全部初始化為負無窮,保證所有狀態從0開始計數
    g[0]=1;
    for(int i=0;i<n;i++){
        int v,w;
        cin>>v>>w;
        for(int j=m;j>=v;j--){
            int t=max(f[j],f[j-v]+w);
            int s=0;//記錄體積為j時方案數
            if(t==f[j])s+=g[j];//如果不拿的話,方案數應該是g[j]的方案數
            if(t==(f[j-v]+w))s+=g[j-v];//如果拿的話,方案數應該是g[j-v]的方案數
            if(s>=mod)s-=mod;//如果s大於mod,那麼減去取得就是模
            f[j]=t;//更新f[j]和g[j]
            g[j]=s;
        }
    }
    
    int maxw=0;
    for(int i=0;i<=m;i++) maxw=max(maxw,f[i]);//選出最大價值 注意:我們並不是一定要用完所有體積,所以最大值應該在0-m去遍歷尋找
    int res=0;
    for(int i=0;i<=m;i++){//再去遍歷一次,找到最大價值時,把最大價值時的方案數加上即可
        if(f[i]==maxw){
           res+=g[i];
           if(res>=mod)res-=mod; 
        } 
    }
    cout<<res<<endl;
    return 0;
}