01背包问题

01背包问题

1.01背包问题介绍

01背包是指有N件物品和一个容量为V的背包。第i件物品的重量是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

01背包中的“01”是指每个物品只能选或不选,也就是选1次和选0次。

2.01背包问题例题

题目描述

一个旅行者有一个最多能装 V 公斤的背包,现在有 N 件物品,它们的重量分别是 W1,W2,...,Wn,它们的价值分别为V1,V2,...,Vn,求旅行者能获得最大总价值。

输入

第一行:两个整数,M(背包容量,M<=200)和 N(物品数量,N<=30);

2..N+1 行:每行二个整数 Wi,Vi ,表示每个物品的重量和价值。

输出

仅一行,一个数,表示最大总价值。

输入样例

10 4
2 1
3 3
4 5
7 9

输出样例

12

注:本题来自AcWing题库第2题

3.01背包问题思路

Dp一般分为两个思考部分

第一个是状态表示,也就是 f 数组。

在01背包问题中,f[i][j] 代表从前 i 个物品中选且总重量不超过 j 的选法集合,它的值是所有算法集合的最大值。

第二个是状态计算,也就是状态转移方程。

前一阶段的终点就是后一阶段的起点,对前一阶段的状态作出某种决策,产生后一阶段的状态,这种关系描述了由k阶段到k+1阶段状态的演变规律,称为状态转移方程。

大致是这个意思,具体可能有错误

01背包问题可以把 f[i][j] 分成含 i 和不含 i 的集合,然后取最大值。所以动态转移方程为:

f[i][j]=max(f[i1][j],f[i1][jv[i]]+w[i])

f[i1][j]:在这个集合里取不含 i 的小集合。

f[i1][jv[i]]+w[i]:用Y总的话来说就是“曲线救国”。要想直接求含 i 的集合很难,所以我们可以先将第 i 个物品的重量减去,再在不含 i 的集合里找,最后加上 i 的权重就好了。

注:在集合的划分上一般要做到不重不漏,只有个别情况不用

4.01背包问题代码

#include<iostream>
#define MAXN 1005
using namespace std;
int v[MAXN],w[MAXN],f[MAXN][MAXN];
int main(){
int n,m;
cin>>m>>n;
for(int i=1;i<=n;i++)
cin>>v[i]>>w[i];
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
f[i][j]=f[i-1][j];
if(j>=v[i]) f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
}
}
cout<<f[n][m];
return 0;
}

5.01背包问题优化

我们通过观察可以得出,f 数组的第一维只用到了 i1,所以我们可以用滚动数组存储,优化掉第一维。

状态转移方程:

f[j]=max(f[j],f[jv[i]]+w[i])

6.代码(优化)

#include<iostream>
using namespace std;
const int MAXN=1005;
int v[MAXN],w[MAXN],f[MAXN];
int main(){
int n,m;
cin>>m>>n;
for(int i=1;i<=n;i++)
cin>>v[i]>>w[i];
for(int i=1;i<=n;i++)
for(int j=m;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+w[i]);
cout<<f[m];
return 0;
}

完awa~

如果觉得好就点个赞吧,您的支持就是本蒟蒻最大的动力。

posted @   Rainforests  阅读(231)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示