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)时的最大值
下面出现了以下几个问题
- max(v-t)怎么求得(现在我们只知道max1)
- 为什么最大值会产生在{ max1,max(v-t)+w}之间,为什么不是背包容量扩大后,选取了其他的物品?
下面来分析一下这两个问题 - 首先(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];
}