背包问题(一)

 题目一   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

分析 :

 如果当前j大于v的情况下,可以得出状态转移方程为f[i,j]=max(f[i-1,j],f[i-1,j-v]+w)

否则,f[i,j]=f[i-1,j]

代码:

#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;const int N=1010;int v[N],w[N];
int f[N][N];
int n,m;int main()
{cin>>n>>m;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]<<endl;return 0;
}

优化成一维: 

观察代码,可以发现只用到了前一维的状态,所以我们可以去掉第一维

此时状态为,前n件物品中总价值不超过j的状态

我们去掉一维之后,注意j要逆序枚举,由于我们的状态转移方程是f[j]=max(f[j],f[j-v[i]]+w[i]);

如果不逆序枚举的话,f[j-v[i]]本来应该是第i-1轮的状态,但是会成为第i轮的状态,即污染。

代码:

#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;const int N=1010;int f[N];
int w[N];
int v[N];int main()
{int n,m;cin>>n>>m;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["<<j<<"]:"<<f[j]<<endl;}cout<<f[m]<<endl;
}

题目二  完全背包 

有 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

分析: 

 

看分析,三重循环才能搞定

优化为二重循环

f[i-1,j-x*v]+x*w=max(f[i,j-v]+w)

如果 j 大于 v ,f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);

否则  f[i][j]=f[i-1][j];

代码:
 

#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;const int N=10010;int v[N],w[N];
int n,m;
int f[N][N];int main()
{cin>>n>>m;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][j-v[i]]+w[i]);}cout<<f[n][m]<<endl;return 0;
}

 优化为一维:

与01背包一样,都只用到了一维

但是完全背包表达式中,f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);

用到了第i维的状态,所以正序枚举 j

代码:

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

题目三  多重背包I 

有 N种物品和一个容量是 V 的背包。

第 i 种物品最多有 si件,每件体积是 vi,价值是 wi。

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

输入格式

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

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

输出格式

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

数据范围

0<N,V≤100
0<vi,wi,si≤100

输入样例

4 5
1 2 3
2 4 1
3 4 3
4 5 2

输出样例:

10

分析: 

三重循环,直接得出结果即可

代码:

#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;
const int N=110;
int f[N][N];
int v[N],w[N],s[N];int main()
{int n,m;cin>>n>>m;for(int i=1;i<=n;i++) cin>>v[i]>>w[i]>>s[i];for(int i=1;i<=n;i++)for(int j=0;j<=m;j++)for(int k=0;k<=s[i]&&k*v[i]<=j;k++){f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);}cout<<f[n][m]<<endl;return 0;
}

优化成一维:

和01背包优化方式一样

j要倒序枚举

代码:

#include <iostream>
#include <algorithm>
#include <cstring>using namespace std;const int N=110;int v,w,s;
int f[N];int main()
{int n,m;cin>>n>>m;for(int i=1;i<=n;i++){cin>>v>>w>>s;for(int j=m;j>=1;j--)//看作01背包,从后往前枚举for(int k=0;k<=s&&k*v<=j;k++){f[j]=max(f[j],f[j-k*v]+k*w);}}cout<<f[m]<<endl;return 0;
}

题目四 多重背包II

有 N 种物品和一个容量是 V的背包。

第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。

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

输入格式

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

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

输出格式

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

数据范围

0<N≤1000
0<V≤2000
0<vi,wi,si≤2000

提示:

本题考查多重背包的二进制优化方法。

输入样例

4 5
1 2 3
2 4 1
3 4 3
4 5 2

输出样例:

10

分析:

本题与前面的区别:数据范围变大 

不能把一件物品拆成s个当作01背包来解

可以利用二进制的办法把一件物品分成logs件物品,然后当作01背包解即可

如果s=10,那么可以拆成1 2 4 3 ,注意最后一个要10-1-2-4得到

这样得到的4件物品科比表示0-10这10件物品

所以本题用到的算法是二进制优化

代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>using namespace std;const int N=2010;
int f[N];int n,m;
int v,w,s;struct goods{int v,w;
};int main()
{cin>>n>>m;vector<goods> good;for(int i=1;i<=n;i++){cin>>v>>w>>s;for(int k=1;k<=s;k*=2){s-=k;good.push_back({v*k,w*k});}if(s>0) good.push_back({v*s,w*s});}for(auto g:good){for(int j=m;j>=g.v;j--){f[j]=max(f[j],f[j-g.v]+g.w);}}cout<<f[m]<<endl;return 0;
}

题目五 多重背包III

有 N种物品和一个容量是 V 的背包。

第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。

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

输入格式

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

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

输出格式

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

数据范围

0<N≤1000
0<V≤20000
0<vi,wi,si≤20000

提示

本题考查多重背包的单调队列优化方法。

输入样例

4 5
1 2 3
2 4 1
3 4 3
4 5 2

输出样例:

10

分析: 

本题数据范围更加庞大,单单用二进制优化显然不行

根据题意

f(i,j)=max(f(i−1,j),f(i−1,j−v)+w,⋯,f(i−1,j−sv)+sw)

f(i,j−v)=max(f(i−1,j−v),f(i−1,j−2v)+w,⋯,f(i−1,j−(s+1)v)+sw)

f(i,j−2v)=max(f(i−1,j−2v),f(i−1,j−3v)+w,⋯,f(i−1,j−(s+2)v)+sw)

f(i,r+sv)=max(f(i−1,r+sv),f(i−1,r+(s−1)v)+w,⋯,f(i−1,r)+sw)

f(i,r+(s−1)v)=max(f(i−1,r+(s−1)v),⋯,f(i−1,r)+(s−1)w)

f(i,r+2v)=max(f(i−1,r+2v),f(i−1,r+v)+w,f(i−1,r)+2w)

f(i,r+v)=max(f(i−1,r+v),f(i−1,r)+w)

f(i,r)=f(i−1,r)

其中 r=j mod vi

去掉i-1和w

f(i,r)=fr

f(i,r+v)=max(fr+v,fr)

f(i,r+2v)=max(fr+2v,fr+v,fr)

f(i,r+(s−1)v)=max(fr+(s−1)v,fr+(s−2)v,⋯,fr+(s−1))

f(i,r+sv)=max(fr+sv,fr+(s−1)v,⋯,fr)   (滑动窗口已满)

f(i,r+(s+1)v)=max(fr+(s+1)v,fr+sv,⋯,fr+v)  (滑动窗口已满)

f(i,j−2v)=max(fj−2v,fj−3v,⋯,fj−(s+2)v)  (滑动窗口已满)

f(i,j−v)=max(fj−v,fj−2v,⋯,fj−(s+1)v)  (滑动窗口已满)

f(i,j)=max(fj,fj−v,⋯,fj−sv)  (滑动窗口已满)

观察可发现,我们要求的始终是一个滑动窗口的最大值

那么我们利用滑动窗口来进行优化

第一重循环枚举每个物品

第二重循环确定有几个滑动窗口,由于一个滑动窗口中都是fj−k*v,所以每个滑动窗口对v的模值都相同

第三重循环枚举每个滑动窗口,求每个滑动窗口中的最大值

代码:

#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;const int N=1010,M=20010;
int f[N][M];
int q[M];
int v[M],w[M],s[M];int n,m;int main()
{cin>>n>>m;for(int i=1;i<=n;i++) cin>>v[i]>>w[i]>>s[i];for(int i=1;i<=n;i++){for(int r=0;r<v[i];r++){int hh=0,tt=-1;for(int j=r;j<=m;j+=v[i]){if(hh<=tt&&q[hh]<j-s[i]*v[i]) hh++;while(hh<=tt&&f[i-1][q[tt]]+(j-q[tt])/v[i]*w[i]<=f[i-1][j]) tt--;q[++tt]=j;f[i][j]=f[i-1][q[hh]]+(j-q[hh])/v[i]*w[i];}}}cout<<f[n][m]<<endl;
}

观察代码发现只用到了前i-1维的值,所以同样可以优化为一维,需要备份一下

优化为一维: 

#include <iostream>
#include <algorithm>
#include <cstring>using namespace std;const int N=1010,M=20010;int f[M],g[M];
int v[M],w[M],s[M];
int q[M];
int n,m;int main()
{cin>>n>>m;for(int i=1;i<=n;i++) cin>>v[i]>>w[i]>>s[i];for(int i=1;i<=n;i++){memcpy(g,f,sizeof f);for(int r=0;r<v[i];r++){int hh=0,tt=-1;for(int j=r;j<=m;j+=v[i]){if(hh<=tt&&q[hh]<j-s[i]*v[i]) hh++;while(hh<=tt&&g[q[tt]]+(j-q[tt])/v[i]*w[i]<=g[j]) tt--;q[++tt]=j;f[j]=g[q[hh]]+(j-q[hh])/v[i]*w[i];}}}cout<<f[m]<<endl;
}

附:滑动窗口模版题

给定一个大小为 n≤106的数组。

有一个大小为 k的滑动窗口,它从数组的最左边移动到最右边。

你只能在窗口中看到 k 个数字。

每次滑动窗口向右移动一个位置。

以下是一个例子:

该数组为 [1 3 -1 -3 5 3 6 7],k 为 33。

窗口位置最小值最大值
[1 3 -1] -3 5 3 6 7-13
1 [3 -1 -3] 5 3 6 7-33
1 3 [-1 -3 5] 3 6 7-35
1 3 -1 [-3 5 3] 6 7-35
1 3 -1 -3 [5 3 6] 736
1 3 -1 -3 5 [3 6 7]37

你的任务是确定滑动窗口位于每个位置时,窗口中的最大值和最小值。

输入格式

输入包含两行。

第一行包含两个整数 n 和 k,分别代表数组长度和滑动窗口的长度。

第二行有 n 个整数,代表数组的具体数值。

同行数据之间用空格隔开。

输出格式

输出包含两个。

第一行输出,从左至右,每个位置滑动窗口中的最小值。

第二行输出,从左至右,每个位置滑动窗口中的最大值。

输入样例:

8 3
1 3 -1 -3 5 3 6 7

输出样例:

-1 -3 -3 -3 3 3
3 3 5 5 6 7

 分析:

使用单调队列来求每个窗口中的最大值和最小值

朴素做法:每次遍历一遍窗口中的所有值,求出对应的最大值和最小值

优化:求最大值时,如果即将入队的元素大于队尾元素,队尾元素删去,使得每次入队的元素都是单调递增的,从而每次输出队头即得到最大值

滑动窗口的算法步骤是

首先判断队头是否滑出队列

实现每次入队元素递增或者递减

如果遍历到的元素大于滑动窗口大小,输出队头即可

代码:

#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;const int N=1e6+5;int n,k;
int q[N];
int a[N];int main()
{cin>>n>>k;for(int i=0;i<n;i++) cin>>a[i];int hh=0,tt=-1;for(int i=0;i<n;i++){//判断队头是否已经滑出窗口if(hh<=tt&&q[hh]<i-k+1) hh++;while(hh<=tt&&a[q[tt]]>a[i]) tt--;q[++tt]=i;if(i-k+1>=0) cout<<a[q[hh]]<<' ';}puts("");hh=0,tt=-1;for(int i=0;i<n;i++){//判断队头是否已经滑出窗口if(hh<=tt&&q[hh]<i-k+1) hh++;while(hh<=tt&&a[q[tt]]<a[i]) tt--;q[++tt]=i;if(i-k+1>=0) cout<<a[q[hh]]<<' ';}puts("");
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/5476.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

力扣C++|一题多解之数学题专场(2)

目录 50. Pow(x, n) 60. 排列序列 66. 加一 67. 二进制求和 69. x 的平方根 50. Pow(x, n) 实现 pow(x,n)&#xff0c;即计算 x 的 n 次幂函数&#xff08;即x^n&#xff09;。 示例 1&#xff1a; 输入&#xff1a;x 2.00000, n 10 输出&#xff1a;1024.00000 示例…

听GPT 讲K8s源代码--pkg(八)

k8s项目中 pkg/kubelet/envvars&#xff0c;pkg/kubelet/events&#xff0c;pkg/kubelet/eviction&#xff0c;pkg/kubelet/images&#xff0c;pkg/kubelet/kubeletconfig这些目录都是 kubelet 组件的不同功能模块所在的代码目录。 pkg/kubelet/envvars 目录中包含了与容器运行…

JVM之内存与垃圾回收篇3

文章目录 8 垃圾回收8.1 基本理论8.1.1 对象的finalization机制8.1.2 理解System.gc8.1.3 内存溢出和内存泄漏8.1.4 Stop The World8.1.5 安全点和安全区域8.1.6 Java中的引用 8.2 垃圾回收算法8.2.1 引用计数法8.2.2 可达性分析8.2.2.1 使用MAT查看GC Roots8.2.2.2 使用JProfi…

整车总线系列——FlexRay 四

整车总线系列——FlexRay 四 我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 没有人关注你。也无需有人关注你。你必须承认自己的价值&#xff0c;你不能…

linux:使用docker-compose提示No Space Left on Device

问题&#xff1a; 如标题 参考&#xff1a; How to Fix Docker’s No Space Left on Device Error | Baeldung on Linux

Spring使用注解存储Bean对象

文章目录 一. 配置扫描路径二. 使用注解储存Bean对象1. 使用五大类注解储存Bean2. 为什么要有五大类注解&#xff1f;3.4有关获取Bean参数的命名规则 三. 使用方法注解储存Bean对象1. 方法注解储存对象的用法2. Bean的重命名 在前一篇博客中&#xff08; Spring项目创建与Bean…

TypeScript基础篇 - React-Rollup-TS环境实战

目录 RollupReactTS scripts/rollup.confog.js package.js Rollup 是一个 JavaScript 模块打包器&#xff0c;可以将小块代码编译成大块复杂的代码&#xff0c;例如 library 或应用程序。主要是做组件化的&#xff0c;如vite RollupReactTS scripts/rollup.confog.js // …

nginx 配置 wss加密访问 mqtt

1. 在服务器上部署mqtt服务 2.在宝塔上配置域名证书 3.nginx配置websocket server {listen 80;listen 443 ssl http2;server_name ws-xx.example.com;index index.php index.html index.htm default.php default.htm default.html;root /www/wwwroot/ws-xx.example.com;loca…

windows hadoop 开发测试版快速搭建

1、hadoop 包下载 清华大学开源软件镜像站下载(速度较快&#xff0c;但版本不全)官方各个版本 下载后解压。 添加环境变量 HADOOP_HOME。并将 %HADOOP_HOME%/bin、%HADOOP_HOME%/sbin 添加到 path 中。 ps&#xff1a;本文使用的是 hadoop-3.3.2 2、windows 环境准备 wind…

服务器量化训练操作说明

Freespace服务器预训练主要步骤&#xff1a; 首先登录堡垒机&#xff0c;命令如下&#xff1a; ssh xxxrelay.baidu-int.com &#xff08;xxx为个人邮箱前缀&#xff09; 密码为个人邮箱密码 登录工作机&#xff0c;命令如下&#xff1a; ssh l3yq01-gpu-255-122-22-00.e…

如何在小程序首页隐藏商品分类

​因为在分类页面有显示分类&#xff0c;所以有的商家希望在首页就不显示分类啦。下面就介绍一下如何在首页隐藏商品分类。 在小程序管理员后台->页面设置->首页&#xff0c;显示商品分类设置为否。设置后&#xff0c;在小程序首页商品分类就不会显示啦。注意&#xff1a…

django rest_framework 框架动态设置序列化返回的字段

动态修改字段可以使Django rest框架API像graphQL端点一样&#xff0c;只从模型中检索所需的字段。 一旦序列化器被初始化&#xff0c;就可以使用.fields属性访问序列化器上设置的字段字典。访问和修改此属性允许您动态修改序列化器。 显式地修改fields参数可以帮助您做一些奇…

RDBMS - MySQL

1、为什么推荐MySQL&#xff1f; MySQL是一种广泛使用的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;有几个主要原因导致它被广泛推荐和使用&#xff1a; 开源和免费&#xff1a; MySQL是开源软件&#xff0c;其核心代码可以免费获取和使用。这使得MySQL成…

chrome 网页 无法复制 插件

源码gitee chrome浏览器复制插件: 浏览器页面无法进行复制&#xff0c;该插件可以复制页面文本、代码 下载安装到浏览器&#xff0c;启用插件&#xff0c;可自己修改代码 可能和某些页面本身的复制功能有些冲突&#xff0c;解决中

【微信小程序】使用button组件来实现一个带有点击效果的按钮,按钮中间添加一个大的+号图标

在微信小程序中&#xff0c;你可以使用button组件来实现一个带有点击效果的按钮&#xff0c;并在按钮中间添加一个大的号图标。以下是一个示例代码&#xff1a; <button class"button"><text class"plus"></text> </button>.butt…

关于Integer类的一个有趣的面试问题

相信很多人觉得答案是false&#xff0c;false&#xff0c;因为Integer是一个类&#xff0c;把int类型的数据传给Integer类型的数据会创建一个对象&#xff0c;而a,b,c,d作为引用指向的是不同的地址&#xff0c;所以判断相同得到的结果应该是false 但这个想法就正中下怀了&#…

【Spring篇】初识 Spring IoC 与 DI

目录 一. Spring 是什么 ? 二. 何为 IoC ? 三. 如何理解 Spring IoC ? 四. IoC 与 DI 五 . 总结 一. Spring 是什么 ? 我们通常所说的 Spring 指的是 Spring Framework&#xff08;Spring 框架&#xff09;&#xff0c;它是⼀个开源框架&#xff0c;有着活跃⽽ 庞⼤…

探秘Spring中Bean的注解宝典:解读存取Bean的相关注解及用法

目录 存储Bean对象Controller(控制器存储)Service(服务存储)Repository(仓库存储)Component(组件存储)Configuration(配置存储)Bean重命名Bean 获取Bean对象属性注入构造方法注入Setter注入Resource(注入关键字) 存储Bean对象 将对象存储在 Spring 中&#xff0c;有两种注解类…

opencv实现替换证件照颜色

程序可以实现蓝色底片变为红色底片&#xff08;但有点小bug&#xff09; 修改自&#xff1a;opencv&#xff1a;HSV颜色模型_opencv hsv_君浪的博客-CSDN博客 相关文章&#xff1a;OpenCV Mat数据类型指针ptr的使用_cv::mat ptr_AoboSir的博客-CSDN博客 【OpenCV】HSV颜色识…

【JAVA】【源码学习】Cleaner/Reference

简介 上一篇讲DirectByteBuffer时提到Cleaner用于释放内存&#xff0c;而Cleaner又跟Reference有关&#xff0c;那本篇就学习一下相关知识。 Cleaner 类注释很清楚的说明了&#xff0c;这个是一种轻量级的finalize机制(相对于VM调用而言)&#xff0c;不管是内存还是其它资源…