背包九讲

更新说明:

时间 更新内容
2022年9月15日09点39分 01背包问题
2022年9月15日10点56分 完全背包问题

1. 01背包

更舒适的阅读

有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。

第 i 件物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式

第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。

接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。

输出格式

输出一个整数,表示最大价值。

数据范围

$0<N,V≤1000$
$0<vi,wi≤1000$

输入样例

4 5 1 2 2 4 3 4 4 5

输出样例:

8

题目关键

  • 01背包只有不选与选这两种情况,所以我们只要抓住这两种情况就可以了
  • 选:f[i][j]=f[i-1][j-v[i]]
  • 不选:f[i][j]=f[i-1][j]

#include <bits/stdc++.h> using namespace std; const int N=100010; int f[N]; int w[N],c[N]; int main() { int n,v; cin>>n>>v; for(int i=1;i<=n;i++) cin>>c[i]>>w[i]; for(int i=1;i<=n;i++){ for(int j=v;j>=c[i];j--){//倒着排就可以避免不是f[i]了 /* 上面的for(int j=v;j>=c[i];j--) 已经把循环范围控制在v~c[i]中了,所以这里的 if(j>=c[i]) 就可以省去了 */ f[j]=max(f[j],f[j-c[i]]+w[i]); } }cout<<f[v]; return 0; }

优化

当然我们可以一边输入一边排,这样会简单

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



2. 完全背包问题

更舒适的阅读体验

有 N 种物品和一个容量是 V 的背包,每种物品都有无限件可用。

第 i 种物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式

第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。

接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 种物品的体积和价值。

输出格式

输出一个整数,表示最大价值。

数据范围

$0<N,V≤1000$
$0<vi,wi≤1000$

输入样例

4 5 1 2 2 4 3 4 4 5

输出样例:

10

解体思路(数学归纳法)

  1. 假设前$i-1$个物品之后的所有$f[j]$全部可选
  2. 来证明考虑完第$i$个物品后,所有f[j]可选
    对于某个j,每个最优解包含K个v[i];

闫式dp法

状态转移:
一:f[i][j]=max(f[i-1][j-v[i]+w[i]) 二:max(f[i-1][j-2*v[i]]+2*w[i]) 三:max(f[i-1][j-3*v[i]]+3*w[i]);
还可以等价替换
四:f[i][j-v]=max(f[i-1][j-2*v[i]) 五:max(f[i-1][j-3*v[i]]+3*w[i]) 六:max(f[i-1][j-4*v[i]]+4*w[i]);
那么

二和四相等,三和六相等……


别想当然
他们还是不一样的

上面一列比下面多个$w[i]$!!!!

代码:

#include <bits/stdc++.h> using namespace std; const int N=10010; int f[N]; int w[N],c[N]; int main() { int n,m; cin>>n>>m; for(int i=1;i<=n;i++) cin>>c[i]>>w[i]; for(int i=1;i<=n;i++){ for(int j=c[i];j<=m;j++) { f[j]=max(f[j],f[j-c[i]]+w[i]); } } cout<<f[m]; return 0; }

优化:(同01背包)

#include<bits/stdc++.h> using namespace std; const int MAXN = 10000; int f[MAXN]; // f[i][j], j体积下前i个物品的最大价值 int main() { int n; int m; // 背包体积 cin >> n >> m; for(int i = 1; i <= n; i++) { int v, w; cin >> v >> w; for(int j = v; j <= m; j++) { f[j] = max(f[j], f[j - v] + w); } } cout << f[m] << endl; return 0; }

__EOF__

本文作者yexc
本文链接https://www.cnblogs.com/LuoGuyexc/p/17012348.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   StudyingFaher  阅读(34)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示