关于01背包问题(入门)
huangliwei · · 个人记录
01背包问题
目录
1——问题概览
2——DP实现(状态转移方程推论)
3——对于01背包问题的优化 二维到一维
问题概览
难度:普及 题目:YBT1267 01背包问题(模版)
描述:
一个旅行者有一个最多能装
它们的重量分别是
求旅行者能获得最大总价值。
DP实现(状态转移方程推论)
首先为什么要叫这为01背包问题???
由题可得,对于任一物品只有拿取或者不拿这两种选择(对于一次选择,执行或不执行)
因此也就由"01"代表这个意思了,这是背包问题的root也是最简单的背包问题
如果用普通的搜索来解决,时间复杂度是
思考下,我们可以把问题分阶段为取第
因为前面
但放下也有前提条件,就是第
简易分析得以下结论
A.放不了:直接不放这个物品,最优解——放这个物品前的最优解
B.放得下:
a.先清空背包,只放这个物品,再看看剩余容量能否装下之前的物品,最优解——这个物品的价值+背包剩余容量的最优解
b.不放这个物品,最优解——放这个物品前的最优解
然后,a、b 情况进行比较,选出真正的最优解
设
状态转移方程就是
注:
代码实现如下
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct WC{ll weight,value;};//weight重量 value价值
ll n,m;//n件物品,m背包容量
WC a[205];//存储物品结构体数组
ll DP[205][205];//当操作物品数为i,背包容量为v时所获最大价值
ll maxn(ll x,ll y){
if(x>y){return x;}
else{return y;}
}
int main(){
memset(DP,0,sizeof DP);
cin>>m>>n;
for(int i=1;i<=n;i++){
cin>>a[i].weight>>a[i].value;
}//输入
for(int i=1;i<=n;i++){//递推每一个物品操作,对于任一物品只有拿或不拿两行为
for(int v=1;v<=m;v++){//递推容量的每一种情况
if(a[i].weight>v){//对于当前物品,超过容量上限,放不下的情况
DP[i][v]=DP[i-1][v];//等于上一个物品操作时所获最大价值,相当于没放
}
else{//如果可以放下
DP[i][v]=maxn( DP[i-1][v] , DP[i-1][v-a[i].weight]+a[i].value );
//考虑不放和放哪一个的价值更大,哪个大存哪个
}
}
}
cout<<DP[n][m];//当n个物品都完成操作,且m的容量都被分配时即为最大
//直接输出DP[n][m]
return 0;
}
对于01背包问题的优化 二维到一维
其实对于01背包的时间已经到
我们重新定义
根据我们上文的分析
其中
可知每一次的
但是我们可以使用逆推来省去
这就使得
状态转移方程为:
注:
这样在优化后01背包的空间复杂度为
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct WC{ll weight,value;};//weight重量 value价值
ll n,m;//n件物品,m背包容量
WC a[205];//存储物品结构体数组
ll DP[205];//当背包容量为v下所能获最大价值
ll maxn(ll x,ll y){
if(x>y){return x;}
else{return y;}
}
int main(){
memset(DP,0,sizeof DP);
cin>>m>>n;
for(int i=1;i<=n;i++){
cin>>a[i].weight>>a[i].value;
}//输入
for(int i=1;i<=n;i++){
for(int v=m;v>=a[i].weight;v--){//逆推
DP[v]=maxn(DP[v-a[i].weight]+a[i].value,DP[v]);
}
}
cout<<DP[m];
return 0;
}