彻底搞懂背包问题

01背包问题

众所周知放假早的学校,早已开始寒假,这一天同学AC带着一个购物车来到超市。
这个购物车很神奇,他装东西只需要考虑体积而不用考虑形状。
这个购物车的容积为v。
这个超市有n种商品,每种的体积为t,价钱为w。
AC想看看这个购物车装到极限 最多能花掉多少钱 。
但是他也不想浪费 所以每个东西只装一件 装不满就算了(商品种类少得可怜)。
输入描述:
第一行两个整数1<=n<=1000,1<=v<=1000
第二至n+2行有两个整数1<=t<=1000,1<=w<=1000
输出描述:
输出一个数字代表花掉的钱
示例1
输入
5 6
1 2
2 4
3 4
4 5
5 6
输出
10
01背包问题是动态规划问题的经典题型,动态规划的主要特点是通过子问题的最优解可以推导出(通过递归的方法)整个问题的最优解。
动态规划的一般步骤是逐步尝试下一种情况,并与现在的情况进行比较。
本题来看,题目中有两个自变量,分别是商品种类数n和背包的容量v。
现在先不考虑选用哪个递归地求解子问题。可以先考虑转移方程的写法
首先最终的目标是所花的价钱,假设中间时刻有一个子问题的最优解为:价钱 w=max1
如果此时背包的容量是v,下一个需要尝试的商品是x(假设x的重量是t,价钱是w)
那么通过动态规划的思想,这个最优解的求解公式为
max1=max{ max1,max(v-t)+w};
注:max(v-t)是当背包容量是(v-t)时的最大值
下面出现了以下几个问题

  1. max(v-t)怎么求得(现在我们只知道max1)
  2. 为什么最大值会产生在{ max1,max(v-t)+w}之间,为什么不是背包容量扩大后,选取了其他的物品?
    下面来分析一下这两个问题
  3. 首先(v-t)没有规律可循,所以只能算出所有小于v的最大值,如下表
    注:画表格是动态规划常用的分析方法
    n\v 1 2 3 4 5 6
    第0个 0 0 0 0 0 0
    第一个 22 2 2 2 2 2

显然,只要设置一个备忘录,记录所有的值即可,
2.怎么证明转移方程?
很显然,根据上表当v,n取任意值时,在n-1的情况下,已经讨论了子问题的最优解,
因此,这时,如果有更优的解,就必须将第n个物品带入。
以下是代码

#include <stdio.h>
#include <math.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
struct p{
	int t;
	int w;
};
int main()
{
	p a[1000];
	int n;
	int v;
	cin>>n>>v;
	for( int i=0;i<n;i++){
		cin>>a[i].t>>a[i].w;
		
	}
	int b[1001]={};//体积~~价格最大值; 
	int pre[1010]={};
	int pt=0;
	b[0]=0;
	pre[0]=0;
	int j=0;//j wupin shu
	for( int j=0;j<n;j++){
			for( int i=1;i<=v;i++){
			if(i-a[j].t>=0)
			b[i]=max(pre[i],pre[i-a[j].t]+a[j].w);		
			}
			for(int u=1;u<=v;u++){
				if(b[u]>=pre[u]){
					pre[u]=b[u];
//					cout<<b[u]<<endl;
				}
			}	
	}
	cout<<b[v];
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值