7.背包问题求方案数
问题:
有N件物品和一个容量是V的背包。
每件物品只能用一次,第i件物品的体积是vi,价值是wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包的容量,且价值总和最大。
输出最优选法方案数。注意答案可能很大,请输出答案模10^9+7的结果
输入格式
第一行有两个整数,N,V用空格隔开,分别表示物品数量、背包容积。
接下来有N行,每行两个个整数vi,wi,用空格隔开,分别表示第i件物品的体积、价值。
输出格式
输出一个整数,表示方案数模10^9的结果。
数据范围
0<N,V<=1000
0<V,M<=1000
输入样例
4 5
1 2
2 4
3 4
4 6
输出样例
2
分析思路:
f[i]:体积是恰好j的情况下,最大价值是多少
g[i]:体积是j的情况下, 方案数是多少
第一种决策,最大值和最优解一样
先算选和不选两种方案最大价值是多少,看到底从哪个决策转移过来
假设其中一个比另外一个大 ,只能从其中一种决策转移过来 (选择决策的方案数)
若两种决策答案一样 ,把两种决策方案数都要选择
更新的时候同时需要更新g数组
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1010,mod=1000000009,INF=1000000;
int n,m;
int f[N],g[N]; //g[i]体积是j的情况下 方案数是多少
int main(){ //f[j]体积恰好是j的情况下
cin>>n>>m;
g[0]=1;
//体积是0的方案数只有1种
for(int i=1;i<=m;i++) f[i]=-INF; //f[0]=0,除此之外初始状态记为负无穷,所有状态从0开始更新
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;
if(t==f[j]) s+=g[j]; //两种都选择
if(t==f[j-v]+w) s+=g[j-v]; //第二种决策,最大值和最优解一样,两种都选择
if(s>=mod) s-=mod; //答案和大于10^9,减去这个数
f[j]=t; //记录最优解
g[j]=s; //记录方案数
}
}
//统计最优解方案数,遍历整个数组,最优解不一定是f,不一定要用满f的体积才能得到
int maxw=0;
for(int i=0;i<=m;i++) maxw=max(maxw,f[i]);
int res=0;
for(int i=0;i<=m;i++) //所有等于最优解的方案
if(maxw==f[i])
{
res+=g[i]; //加上体积是i的方案数
if(res>=mod)
res-=mod;
}
cout<<res<<endl;
return 0;
}