九大背包问题专题--背包问题求方案数

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; 
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值