背包问题(一)

 题目一   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;你不能…

Spring使用注解存储Bean对象

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

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…

服务器量化训练操作说明

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参数可以帮助您做一些奇…

关于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;有两种注解类…

【Linux】信号保存信号处理

前言&#xff1a;对信号产生的思考 上一篇博客所说的信号产生&#xff0c;最终都要有OS来进行执行&#xff0c;为什么&#xff1f;OS是进程的管理者&#xff01;信号的处理是否是立即处理的&#xff1f;在合适的时候 -》那什么是合适的时候&#xff1f;信号如图不是被立即处理…

Windows安装RabbitMQ

Windows安装RabbitMQ 前言配置erlang环境下载配置环境变量验证 安装RabbitMQ验证 参考 前言 本文并不涉及到RabbitMQ的底层原理&#xff0c;或者别的一些特性说明&#xff0c;仅仅只是安装。 配置erlang环境 因为RabbitMQ是使用该语言开发的。 下载 下载地址&#xff1a; …

《qt quick核心编程》笔记一

1.基础HelloWorld代码 import QtQuick 2.15 import QtQuick.Window 2.15 import QtQuick.Controls 2.15Window {width: 400height: 300visible: truetitle: qsTr("Hello 1World")Rectangle {width: parent.widthheight: parent.heightcolor: "gray"Text {…

【数据挖掘】bytewax 与 ydata工具可实时了解您的数据

一、说明 在这篇博文中&#xff0c;我们将介绍如何将开源流式处理解决方案 bytewax 与 ydata 分析相结合并加以利用&#xff0c;以提高流式处理流的质量。 STream 处理支持在传输中和存储之前对数据进行实时分析&#xff0c;并且可以是有状态的&#xff0c;也可以是无状态的。 …

【网络编程】网络套接字udp通用服务器和客户端

1.预备知识 认识端口号 端口号(port)是传输层协议的内容&#xff1a; 端口号是一个2字节16位的整数(uint16)端口号用来标识主机上的一个进程IP地址port能够标识网络上的某一台主机和某一个进程一个端口号只能被一个进程占用 认识TCP协议 此处我们先对TCP(Transmission Con…

Spring MVC异步上传、跨服务器上传和文件下载

一、异步上传 之前的上传方案&#xff0c;在上传成功后都会跳转页面。而在实际开发中&#xff0c;很多情况下上传后不进行跳转&#xff0c;而是进行页面的局部刷新&#xff0c;比如&#xff1a;上传头像成功后将头像显示在网页中。这时候就需要使用异步文件上传。 1.1 JSP页面 …

[golang gin框架] 41.Gin商城项目-微服务实战之后台Rbac微服务(用户登录 、Gorm数据库配置单独抽离、 Consul配置单独抽离)

上一节抽离了captcha验证码功能,集成了验证码微服务功能,这一节来看看后台Rbac功能,并抽离其中的用户登录,管理员管理,角色管理,权限管理等功能作为微服务来调用 一.引入 后台操作从登录到后台首页,然后其中的管理员管理,角色管理,权限管理等功能可以抽离出来作为 一个Rbac微服…

Python实战

官方文档 请点击下面工程名称&#xff0c;跳转到代码的仓库页面&#xff0c;将工程 下载下来 Demo Code 里有详细的注释 LearnPythonPython 实现功能点demo