【No.16】蓝桥杯动态规划下|线性DP装箱问题|计数DP0/1背包的方案数|过河卒|完全背包小明的背包2|最长公共子序列|蓝桥骑士|推荐练习题(C++)

线性DP,0/1背包简化版,装箱问题

【题目描述】有一个箱子容量为V(正整数, 0 ≤ V ≤ 20000 0 \le V \le 20000 0V20000),同时有n个物品( 0 < n ≤ 30 0 < n \le 30 0<n30),每个物品有一个体积(正整数)。要求 n 个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。
【输入描述】输入第一行,一个整数,表示箱子容量。
第二行,一个整数n,表示有n个物品。
接下来n行,分别表示这n个物品的各自体积。
【输出描述】输出一行,表示箱子剩余空间。
0/1背包的简化版,不管物品的价格。把体积(不是价格)看成最优化目标:最大化体积。

#include<bits/stdc++.h>
using namespace std;
int dp[20010];
int w[40];
int main()
{int V,n;scanf("%d%d" ,&V,&n);for(int i = 1; i <= n; i ++)scanf("%d",&w[i]);for(int i = 1; i <= n; i ++)for(int j = V; j >= w[i]; j --)dp[j] = max(dp[j], dp[j-w[i]]+w[i])printf("%d\n", V-dp[V]);return 0;
}
计数DP,0/1背包的方案数

【题目描述】
将2022拆分成10个互不相同的正整数之和,总共有多少种拆分方法?
注意交换顺序视为同一种方法。
例如:
2022 = 1000+1022
2022 =1022+1000
视为同一种方法。

题目求10个数的组合情况,这十个数相加等于2022。因为是填空题可以不管运行时间,看起来可以用暴力for循环10次,加上剪枝。
然而暴力的时间极长,因为答案是:379187662194355221

这一题其实是0/1背包:
背包容量为2022,物品体积为1~2022,往背包中装10个物品,要求总体积为2022,问一共有多少种方案。

定义dp[][][]: dp[i][j][k]表示数字1~i取j个,和为k的方案数。下面的分析沿用标准0/1背包的分析方法,
从i-1扩展到i,分两种情况:

  1. k ≥ i k \ge i ki。数i可以要,也可以不要
    1. 要i。从1~i-1中取j-1个数,再取i,等价于dp[i-1][j-1][k-i]
    2. 不要i。从1~i-1中取j个数,等价于dp[i-1][j][k]
    3. 合起来:dp[i][j][k]= dp[i-1][j][k]+ dp[i-1][j-1][K-i]
  2. k < i.
    由于数i比总和k还术、显然i不能用。
    有:dp[i][j][k]= dp[i-1][j][k]
for (int i = 0; i <= 2022; i ++)dp[i][0][0] = 1;   //特别注意这个初始化

1~i个数,选0个和为0的情况只有一种,就是不选

(1)k≥i。dp[i][j][k]= dp[i-1][j][k]+ dp[i-1][j-1][k-i]
(2)k<i。dp[i][j][k]= dp[i-1][j][k]

不用滚动数组
#include <bits/stdc++.h>
using namespace std;
long long dp[2222][11][2222]={0};
int main()
{for(int i = 0; i <= 2022; i ++)dp[i][0][0] = 1;    //特别注意这个初始化for(int i = 1; i <= 2022; i ++)for(int j = 1; j <= 10; j ++)  //注意:j从小到大,或从大到小都行for(int k = 1; k <= 2022; k ++){if(k<i)dp[i][j][k] = dp[i-1][j][k]; //无法装进背包elsedp[i][j][k] = dp[i-1][j][k] + dp[i-1][j-1][k-i];cout << dp[2022][10][2022];return 0;
}
使用滚动数组
#include <bits/stdc++.h>
using namespace std;
long long dp[11][2222];
int main()
{dp[0][0]=1;for(int i = 1; i <= 2022; i ++)for(int j = 10; j >= 1; j --) //j一定要从大到小for(int k = i; k <= 2022; k ++)dp[j][k] += dp[j-1][k-i];cout << dp[10][2022];return 0;
}
网格上的DP,过河卒

【题目描述】
棋盘上A点有一个过河卒,需要走到目标B点。
卒行走的规则:可以向下、或者向右。同时在棋盘上C点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。
现在要求你计算出卒从 A点能够到达B点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。棋盘用坐标表示,A点(0,0)、B点(n,m),同样马的位置坐标是需要给出的。1≤n,m≤20,0≤马的坐标≤20。【输入格式】
一行四个正整数,表示B点坐标和马的坐标。
【输出格式】
一个整数,表示所有的路径条数。
![[Pasted image 20240323150439.png]]

统计路径条数,看起来是个搜索题,可以用DFS求解。把马的控制点标记为不能走,绕过它们。
不过,用DFS搜索的路径数量是天文数字,肯定超时
在小学上过奥数的都知道,这题应该用“标数法”,就是在每个坐标点上记录能走的路径条数。
标数法实际上就是DP的递推。

定义状态dp[][]:
dp[i][j]表示卒走到坐标(i,j)时能走的路径条数。
如果不考虑马的控制点,有:dp[i][j]= dp[i-1][j]+ dp[i][j - 1]
也就是(i,j)点的路径条数等于它上面和左边的路径条数之和。这就是小学奥数的“标数法”的原理
本题的限制条件是马的控制点,只要令控制点的dp[i][j] = 0即可,即这个点上无路径

#include <bits/stdc++.h>
using namespace std;
long long dp[25][25];
bool s[25][25];  //标记马的9个控制点
int main()
{int bx,by,mx,my;scanf("%d%d%d%d",&bx,&by,&mx,&my);bx += 2;by += 2;mx += 2;my += 2;//技巧:坐标点加2,防止越界,因为马能向上向左跳2格dp[2][1] = 1;  	//初始化s[mx][my] = 1;	//标记马的控制点s[mx - 2][my + 1] = 1;s[mx - 2][my - 1] = 1;S[mx + 2][my - 1] = 1;s[mx + 2][my + 1] = 1;s[mx - 1][my - 2] = 1;s[mx - 1][my + 2] = 1;s[mx + 1][my + 2] = 1;s[mx + 1][my - 2] = 1;for(int i = 2; i <= bx; i ++)for(int j = 2; j <= by; j ++){if(s[i][j])dp[i][j] = 0;  //这个点是控制点,不能走elsedp[i][j] = dp[i-1][j] + dp[i][j - 1];}printf("%lld\n", dp[bx][by]);  //结果是个极大的数字return 0;
}
完全背包,小明的背包2

【题目描述】
小明有一个容量为C的背包。这天他去商场购物,商场一共有N 种物品,第i种物品的体积为 c i c_{i} ci,价值为 w i w_{i} wi,每种物品都有无限多个。小明想知道在购买的物品总体积不超过C的情况下所能获得的最大价值为多少,请你帮他算算。
【输入描述】
输入第1行包含两个正整数N,C,表示商场物品的数量和小明的背包容量。
第2~N+1行包含2个正整数c,w,表示物品的体积和价值。
1≤N≤103,1≤C≤103,1≤ci,wi≤10^3
【输出描述】
输出一行整数表示小明所能获得的最大价值

思路和0/1背包类似。0/1背包的每种物品只有1件,完全背包的每种物品有无穷多件,第i种可以装0件、1件、2件、C/ c i c_{i} ci件。
定义dp[i][j]:把前i种物品(从第1种到第i种)装入容量为j的背包中获得的最大价值。
把每个dp[i][j]都看成一个背包:背包容量为j,装1~i这些物品。最后得到的dp[N][C]就是问题的答案:把N种物品装进容量c的背包的最大价值。
在0/1背包问题中,每个物品只有拿与不拿两种;而完全背包问题,需要考虑拿几个。

1.定义变量并输入
参考 0-1 背包。
2.执行算法
我们先去找到状态转移方程

dp[i][j]=max(dp[i], dp[i][j-c[i]]+w[i])

选到第i件物品,且背包现在重是为j。
那么考虑这个状态会由什么状态转移而来,肯定是选到第 i-1 件的时候,或者选了若干次第i件
如果不选第i种,那么就是由dp[i-1][i]转移而来
如果选了第i件,那么就是由dp[i-1][j-c[i]]转移而来。
或者在某一刻,不在选第i件了,那么就是有dp[i][j]转移而来。
那么已知dp[i][j-c[i]]dp[i][j]都为各自最优的状态,那我们直接取最优状态即可

#include <iostream>
#include <cstring>using namespace std;
#define Maxn 5000;int c[Maxn], w[Maxn];
int dp[Maxn][Maxn];
int C;int n;int main()
{cin >> n;cin >> C;for (int i = 1; i <= n; i ++)cin >> c[i] >> w[i];memset(dp, 0, sizeof(dp));for (int i = 1; i <= n; i ++){for (int j = 1; j <= C; j ++){dp[i][j] = dp[i - 1][j];if (j >= c[i])dp[i][j] = max(dp[i][j], dp[i][j-c[i]] + w[i]);}}cout << dp[n][C] << endl;
}

因为状态转移每次只与上一层有关,所以用一个一维数组就可以。
为什么从小到大遍历,看

dp[j]=dp[j-c[i]]+w[i]

这一状态转移,是根据小的改大的,而此时的含义为选了x件后的容量与质量,跟01背包类似,但含义不同,处理方式上也有本质区别,处理完一件后在处理下件。

#include <iostream>
#include <cstring>using namespace std;
#define Maxn 5000;int c[Maxn], w[Maxn];
int dp[Maxn];
int C;int n;int main()
{cin >> n;cin >> C;for (int i = 1; i <= n; i ++)cin >> c[i] >> w[i];memset(dp, 0, sizeof(dp));for (int i = 0; i < n; i ++) //遍历每一件物品{//遍历背包容量,在上一层的基础上,容量为j时,第i件物品装或不装的最优解for (int j = c[i]; j <= C; j ++){dp[j] = max(dp[j-c[i]] + w[i], dp[j]);}}cout << dp[C] << endl;
}
线性DP,最长公共子序列

【题目描述】
给定一个长度为n的数组A和一个长度为m的数组B。请你求出它们的最长公共子序列长度为多少
【输入描述】
输入第一行包含两个整数n、m。
第二行包含n个整数ai,
第三行包含m个整数bi,
1≤n,m≤103,1≤ai,bi≤109
【输出描述】
输出一行整数表示答案。

暴力法:先找出A的所有子序列,然后一一验证是否为Y的子序列。
如果A有m个元素,那么A有 2 m 2^{m} 2m个子序列;B有n个元素;总复杂度大于 O ( n ∗ 2 m ) O(n*2^m) O(n2m).

dp[i][j]:房列Ai(a1ai)和Bj(b1bj)的最长公共子序列的长度。
答案:dp[n][m]
分解为2种情况

  1. a i = b j a_{i}=b_{j} ai=bj;时已求得 A i − 1 A_{i-1} Ai1 B j − 1 B_{j-1} Bj1的最长公共子序列,在其尾部加上 a i a_{i} ai b j b_{j} bj即可得到Ai和Bj的最长公共子序列。 状态转移方程:
    dp[i][j]=dp[i-1][j-1]+ 1
  2. a i ≠ b j a_{i}\ne b_{j} ai=bj时,求解两个子问题: A i − 1 A_{i-1} Ai1 B j B_{j} Bj的最长公共子序列; A i A_{i} Ai B j − 1 B_{j-1} Bj1的最长公共子序列。取最大值,状态转移方程:
    dp[i][j]= max(dp[i][j-1], dp[i-1][j])
#include <iostream>
#include <cstring>
using namespace std:
#define Maxn 5000int dp[Maxnl[Maxn];
//DP 辅助数组
int a[Maxn], b[Maxn];int main()
{int n, m;cin >> n >> m;for(int i = 0; i < n; i ++)cin >> a[i];for(int i = 0; i < m; i ++)cin >> b[i];dp[0][0] = 0;for (int i = 0; i < n; i ++)for (int j = 0; j < m; j ++)if (a[i] == b[j])dp[i + 1][j + 1] = dp[i][j] + 1;elsedp[i + 1][j + 1] = max(dp[i + 1][j], dp[i][j + 1]);cout << dp[n][m]<< endl;
}
最长递增子序列,蓝桥骑士

【题目描述】
小明是蓝桥王国的骑士,他喜欢不断突破自我。这天蓝桥国王给他安排了N个对手,他们的战力值分别为 a 1 , a 2 , . … ,, a n a_{1},a_{2},.…,,a_{n} a1a2.,,an,且按顺序阻挡在小明的前方。对于这些对手小明可以选择挑战,也可以选择避战。身为高傲的骑士,小明从不走回头路,且只愿意挑战战力值越来越高的对手。
请你算算小明最多会挑战多少名对手。
【输入描述】
第一行是整数N,表示对手的个数,第二行是N个整数 a 1 , a 2 , . … ,, a n a_{1},a_{2},.…,,a_{n} a1a2.,,an,表示对手战力值。1≤N≤3x10^5
【输出描述】
输出一行整数表示答案。

求一个子序列,保证这个子序列时递增的,最长是多少

给定一个长度为n的数组,找出一个最长的单调递增子序列。
例:序列A={5,6,7,4,2,8,3},它最长的单调递增子序列为{5,6,7,8},长度为4。
定义状态dp[i]:表示以第i个数为结尾的最长递增子序列的长度。
状态转移方程:
dp[i]= max{dp[j]}+1, 0<j<i, A < Ai
答案:max{dp[i]}
复杂度:
j在0~i之间滑动,复杂度O(n);
i的变动范围也是O(n)的;
总复杂度O(n2)

我们首先定义状态:
我们定义dp[i]为以a[i]结尾的最长上升子序列长度。
设置j为小于i的某一点,那么当 a[j]<a[i] 时,必然有,以 a[j] 结尾的最长上升子序列,现在能以 a[i] 结尾,并且长度 +1。
因为 j<i且 a[j]< a[i],满足上升子序列的要求。
所以 dp[i] 的一条转移路径为 dp[i]=dp[j]+1
但是j是比i小的某一个值,所以转移到 dp[i] 这一状态的值很多,我们要选择最优状态,所以 dp[i]的状态转移:
dp[i]=max(dp[j]+1, dp[i]);
那么当 a[j]>a[i]
此时肯定不满足上升子序列,所以 dp[i]dp[j] 毫无关联。由此我们可以写出 LIS 的算法部分

#include <bits/stdc++.h>using namespace std;
//求最长升序子序列的长度,并输出
#define Maxn 300006
int a[Maxn];
int dp[Maxn];
int ans=1:
int main()
{int m, k;int n;cin >> n;for(int i = 0; i < n; i ++){cin >> a[i];dp[i] = 1;}for(int i = 1; i < n; i ++){for(int j = 0; j < i; j ++){if(a[j] < a[i]){dp[i] = max(dp[j] + 1, dp[i]);}ans=max(ans, dp[i]);}}cout << ans << endl;:
}
练习题
  1. 李白打酒加强版2114
  2. 分果果1459
  3. 开心的金明554
  4. 最优包含239
  5. 质数行者1027
  6. 货币系统331
  7. 合唱队形742
  8. 数组切分2148
  9. 括号序列1456
  10. 传球游戏525
  11. 画廊1032
  12. 游园安排1024
  13. 凑硬币1082
  14. 纪念品786。
  15. 积木画2110
  16. 采药563
  17. 摆花389;
  18. 蓝肽子序列1030
  19. 矩阵计数246
  20. 方格取数803

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

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

相关文章

【web前端】CSS语法

CSS语法 1. CSS语法格式 通常情况下语法格式如下: 选择器{属性名:属性值;属性名:属性值;属性名:属性值;... }2. CSS添加方式 2.1 行内样式 直接将样式写在本行的标签内。 <h1><p style"font-size: 48px; color:red;";>行内样式测试</p></…

RHEL9部署Docker环境

华子目录 Docker引擎架构docker引擎架构示意图执行过程示例 RHEL9上安装Docker1.系统要求2.安装yum-utils工具包3.yum安装docker-ce4.配置docker镜像加速docker拉取镜像的过程配置阿里云镜像仓库重新加载守护进程重启Docker服务 5.拉取并运行hello-world镜像6.测试是否安装成功…

SpringCloudAlibaba和SpringCloud的区别

SpringCloudAlibaba实际上对SpringCloud实现拓展组件功能. 1.nacos 分布式配置中心分布式注册中心Eurekaconfig 2.目的是为了推广阿里的产品&#xff0c;如果使用了SpringCloudAlibaba,最好使用alibaba整个体系产品 SpringCloudAlibaba版本对应: 2020.0 分支对应的是 Spring…

ElasticSearch首次启动忘记密码,更改密码(Windows 10)

先启动ElasticSearch 启动方式cmd到lasticsearch-8.12.2\bin目录下输入elasticsearch 启动成功后新开一个窗口输入elasticsearch-reset-password -u elastic

长安链共识算法切换:动态调整,灵活可变

#功能发布 长安链3.0正式版发布了多个重点功能&#xff0c;包括共识算法切换、支持java智能合约引擎、支持后量子密码、web3生态兼容等。我们接下来为大家详细介绍新功能的设计、应用与规划。 随着长安链应用愈加成熟与广泛&#xff0c;一些在生产中很实用的需求浮出水面。长安…

RIPGeo代码理解(五)utils.py( 辅助函数)第一部分

​ 代码链接:RIPGeo代码实现 ├── lib # 包含模型(model)实现文件 │ |── layers.py # 注意力机制的代码。 │ |── model.py # TrustGeo的核心源代码。 │ |── sublayers.py # layer.py的支持文件。 │ |── utils.p…

Linux发布项目(包括前端和后端)到OpenEuler虚拟机上

后端&#xff1a;SpringBoot 前端&#xff1a;VUE3 操作系统&#xff1a;Linux 虚拟机&#xff1a;OpenEuler 发布项目是需要关闭虚拟机上的防火墙 systemctl stop firewalld 一、发布后端项目到虚拟机 1打包后端项目为jar包 2将打包后的jar包放到虚拟机 /opt 目录下 3 运行项…

算法体系-12 第 十二 二叉树的基本算法 下

一 实现二叉树的按层遍历 1.1 描述 1&#xff09;其实就是宽度优先遍历&#xff0c;用队列 2&#xff09;可以通过设置flag变量的方式&#xff0c;来发现某一层的结束&#xff08;看题目&#xff09;看下边的第四题解答 1.2 代码 public class Code01_LevelTraversalBT {publ…

Elsevier(爱思唯尔)如何查询特刊special issue

1. 以Knowledge-Based Systems为例 网站&#xff1a;https://www.sciencedirect.com/journal/knowledge-based-systems 2.具体位置

Linux进程间通信【一】

进程间通信介绍 进程间通信的概念 进程间通信简称IPC&#xff08;Interprocess communication&#xff09;&#xff0c;进程间通信就是在不同进程之间传播或交换信息。 进程间通信的目的 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程资源共享&#xff1a;多…

linux内核input子系统概述

目录 一、input子系统二、关键数据结构和api2.1 数据结构2.1.1 input_dev2.1.2 input_handler2.1.3 input_event2.1.4 input_handle 2.2 api接口2.2.1 input_device 相关接口input_device 注册流程事件上报 2.2.2 input handle 相关接口注册 handle指定 handle 2.2.3 input han…

基于springboot+vue的电影院购票系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

数码管的动态显示

1.共阴极数码管实现HELLO #include<reg51.h> char str[]{0x76,0x79,0x38,0x38,0x3F}; //HELLO char wei[]{0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; void delay(int n) {int i0,j0;for(i0;i<n;i){for(j0;j<120;j);} } void seg() {int i;for(i0;i<…

NC 现金流量查询 节点 多账簿联查时,根据所选择的列来判断明细和现金流量联查按钮是否可用,根据添加列选择监听事件处理。

NC 现金流量查询 节点 多账簿联查时&#xff0c;根据所选择的列来判断明细和现金流量联查按钮是否可用&#xff0c;如下图的情况&#xff1a; 在现金流量查询界面UI类的initTable(QueryConditionVO conVO)方法中添加列选择监听事件即可&#xff0c;如下&#xff1a; // 列监听…

LeetCode刷题【树状数组、并查集、二叉树】

目录 树状数组307. 区域和检索 - 数组可修改406. 根据身高重建队列673. 最长递增子序列的个数1409. 查询带键的排列 并查集128. 最长连续序列130. 被围绕的区域 二叉树94. 二叉树的中序遍历104. 二叉树的最大深度101. 对称二叉树543. 二叉树的直径108. 将有序数组转换为二叉搜索…

web性能检测工具lighthouse

About Automated auditing, performance metrics, and best practices for the web. Lighthouse 可以自动检查Web页面的性能。 你可以以多种方式使用它。 浏览器插件 作为浏览器插件&#xff0c;访问chrome网上商店 搜索Lighthouse 插件安装。以两种方式使用。 方式一 安装…

DP:路径规划模型

创作不易&#xff0c;感谢三连支持&#xff01; 路径规划主要是让目标对象在规定范围内的区域内找到一条从起点到终点的无碰撞安全路径。大多需要用二维dp数组去实现 一、不同路径 . - 力扣&#xff08;LeetCode&#xff09;不同路径 class Solution { public:int uniquePath…

重学SpringBoot3-MyBatis的三种分页方式

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-MyBatis的三种分页方式 准备工作环境搭建数据准备未分页效果 1. 使用MyBatis自带的RowBounds进行分页演示 2. 使用物理分页插件演示 3. 手动编写分页SQL…

pcl 凸包ConvexHull

pcl 凸包ConvexHull 头文件等 #include <pcl/surface/convex_hull.h>typedef pcl::PointXYZ PointT; typedef pcl::PointCloud<PointT> CloudT; typedef CloudT::Ptr CP 代码 CP PSO::tubao(CP cloud) {pcl::ConvexHull<PointT> hull;hull.setInputCloud…

代码随想录算法训练营第十七天|110.平衡二叉树、257.二叉树的所有路径、404.左叶子之和

代码随想录算法训练营第十七天|110.平衡二叉树、257.二叉树的所有路径、404.左叶子之和 110.平衡二叉树 给定一个二叉树&#xff0c;判断它是否是 平衡二叉树 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;true题解&#xff1a;平衡…