当前位置: 首页 > news >正文

【动态规划】详解 0-1背包问题

文章目录

  • 1. 问题引入
  • 2. 从 dfs 到动态规划
  • 3. 动态规划过程分析
  • 4. 二维 dp 的遍历顺序
  • 5. 从二维数组到一维数组
  • 6. 一维数组的遍历次序
  • 7. 背包的遍历顺序
  • 8. 代码总结
  • 9. 总结


1. 问题引入

0-1 背包是比较经典的动态规划问题,这里以代码随想录里面的例子来介绍下。总的来说就是:有 n 个物品和一个重量为 w 的背包,这 n 个物品中第 i 个物品的重量为 w[i],价值为 v[i],那么这个背包能装下的物品最大价值是多少,注意一个物品只能选一次。
在这里插入图片描述


2. 从 dfs 到动态规划

我们来把问题具体化,假设现在有一个重量为 4 的背包,有 3 个物品,物品的重量和价值如下:

重量价值
物品 0115
物品 1320
物品 2430

那么现在将物品装入背包,能装入的物品的最大价值是多少呢?要想解决动态规划问题,我们总得从 dfs 入手,那就先从 dfs 讲讲。

public class Main {public static void main(String[] args) {Main main = new Main();main.findMax(new int[]{1, 3, 4}, new int[]{15, 20, 30}, 4);main.findMax(new int[]{1, 3}, new int[]{15, 20}, 3);}public void findMax(int[] weight, int[] prices, int max){int res = dfs(weight, prices, max, weight.length - 1);System.out.println("最大价值是: " + res);}private int dfs(int[] weight, int[] prices, int max, int i) {if(i < 0){// 遍历到尾部了return 0;}// 不选当前的价值int noPick = dfs(weight, prices, max, i - 1);// 如果剩余重量大于 weight[i] 才可选return max >= weight[i] ? Math.max(prices[i] + dfs(weight, prices, max - weight[i], i - 1), noPick) : noPick;}
}

dfs 的遍历逻辑很简单,就是从后往前遍历,然后对于当前物品,可以选或者不选,但是有条件,如果选的话剩余的容量必须要大于 weight[i],否则就不能选,因为剩余重量装不下当前物品。

但是我们知道,这个方法是会超时的,如果数组长度比较大,因为里面有不少重复计算,既然这样我们就加上记忆化搜索

public class Main {public static void main(String[] args) {Main main = new Main();main.findMax(new int[]{1, 3, 4}, new int[]{15, 20, 30}, 4);main.findMax(new int[]{1, 5}, new int[]{15, 20}, 3);}public void findMax(int[] weight, int[] prices, int max){// memo[i][j] 的意思是从 [0...i] 中将物品放到重量为 j 的背包,最大值是多少int[][] memo = new int[weight.length][max + 1];for (int[] arr : memo) {Arrays.fill(arr, -1);}int res = dfs(weight, prices, max, weight.length - 1, memo);System.out.println("最大价值是: " + res);}private int dfs(int[] weight, int[] prices, int max, int i, int[][] memo) {if(i < 0){// 遍历到尾部了return 0;}if(memo[i][max] != -1){return memo[i][max];}// 不选当前的价值int noPick = dfs(weight, prices, max, i - 1, memo);return memo[i][max] = (max >= weight[i] ? Math.max(prices[i] + dfs(weight, prices, max - weight[i], i - 1, memo), noPick) : noPick);}
}

好了,在记忆化搜索的基础上,我们再来改造成动态规划,首先我们看上面的 dfs 逻辑,当前 i 的结果是基于 i - 1 得来的,也就是说我们可以得到下面的递推公式:

  • d p [ i ] [ j ] = M a t h . m a x ( d p [ i − 1 ] [ j ] , p r i c e s [ i ] + d p [ i − 1 ] [ j − w e i g h t [ i ] ] ) dp[i][j] = Math.max(dp[i-1][j], prices[i] + dp[i-1][j-weight[i]]) dp[i][j]=Math.max(dp[i1][j],prices[i]+dp[i1][jweight[i]])
  • 上面的意思是如果不选当前下标 i 的物品,那么就继续往前找
  • 如果选当前下标 i 的物品,那么价值就是 prices[i],接着 j 要减去物品 i 的价值

好了,递推公式有了,那么如何初始化呢?我们知道 dp[i][j] 的意思是:在下标 [0…i] 中选择物品装入重量为 j 的背包,能装入的最大值是多少!

  • 当 i = 0 的时候,dp[0][j] 表示下标 0 物品装入重量为 j 的背包,最大值是多少。
  • 当 j = 0 的时候,dp[i][0] 表示下标 [0…i] 的物品装入重量为 0 的背包,最大值是多少,自然是 0 了。

所以初始化如下:

int[][] dp = new int[weight.length][max + 1];
for(int j = 0; j <= max; j++){if(j > weight[0]){dp[0][j] = prices[i];}
}

下面再结合记忆化搜索的代码,就能写出来下面的动态规划代码。

public int findMaxD(int[] weight, int[] prices, int max){int[][] dp = new int[weight.length][max + 1];for(int j = 0; j <= max; j++){if(j >= weight[0]){dp[0][j] = prices[0];}}// 遍历物品for(int i = 1; i < weight.length; i++){// 遍历背包for(int j = 0; j <= max; j++){if(j < weight[i]){dp[i][j] = dp[i - 1][j];} else {dp[i][j] = Math.max(dp[i - 1][j], prices[i] + dp[i - 1][j - weight[i]]);}}}return dp[weight.length - 1][max];
}

3. 动态规划过程分析

上面我们写出了动态规划的代码,但是不知道大家有没有疑问,就是这个物品和背包的遍历是有顺序的吗?注意我这里指的是二维的 dp 数组,现在我们讨论都是在二维 dp 的基础上去讨论,后面会逐步演变成一维 dp。

首先就是递推公式

  • d p [ i ] [ j ] = M a t h . m a x ( d p [ i − 1 ] [ j ] , p r i c e s [ i ] + d p [ i − 1 ] [ j − w e i g h t [ i ] ] ) dp[i][j] = Math.max(dp[i-1][j], prices[i] + dp[i-1][j-weight[i]]) dp[i][j]=Math.max(dp[i1][j],prices[i]+dp[i1][jweight[i]]),根据这个递推公式,

通过这个递推公式,我们能发现 dp[i][j] 其实依赖当前格子的上边和左上的格子
在这里插入图片描述
那么从这个角度,我们再来看动态规划的初始化,你就知道为什么要初始化 i = 0 和 j = 0 的格子值了(j = 0 不需要初始化,因为都是 0)。
在这里插入图片描述
初始化完第一行之后,再从第二行开始通过递推公式填充格子,最终填充好的结果如下所示:
在这里插入图片描述
我用下标 (1,3)举个例子,当 i = 1,j = 3 的时候,如果不选当前物品,那么就是 dp[0][3],如果选当前物品,那么就是 dp[1 - 1][3 - 3] + 20 = 20,两者取最大值就是 20,遍历顺序是从左到右,从上到下


4. 二维 dp 的遍历顺序

好了,上面我们解析了 dp 数组的填充过程,那么如果是先遍历物品,再遍历背包,填充的过程就是 从左到右,从上到下。那么如果是先遍历背包,再遍历物品呢?

还是回到 dp 图,如果先遍历背包,再遍历物品,其实就是从从上到下,从左到右
在这里插入图片描述
那么我们想一下,如果是这种遍历顺序,在遍历到 dp[1][3] 的时候,dp[0][3] 和 dp[0][0] 初始化了吗,换句话说,当遍历到第 i 行的时候,第 i - 1 行初始化了吗?

从遍历过程就能看到,其实是初始化了的,所以我们先遍历背包,再遍历物品也是没问题的。如何遍历,遍历顺序是什么就取决于当遍历到(i,j)的时候,需要依赖的格子有没有初始化。

public int findMaxD(int[] weight, int[] prices, int max) {int[][] dp = new int[weight.length][max + 1];for (int j = 0; j <= max; j++) {if (j >= weight[0]) {dp[0][j] = prices[0];}}// 遍历背包for (int j = 0; j <= max; j++) {// 遍历物品for (int i = 1; i < weight.length; i++) {if (j < weight[i]) {dp[i][j] = dp[i - 1][j];} else {dp[i][j] = Math.max(dp[i - 1][j], prices[i] + dp[i - 1][j - weight[i]]);}}}return dp[weight.length - 1][max];
}

那么我再问一句,遍历背包能倒叙遍历吗?其实从 dp 数组的依赖就能看出,可以!!! 因为第 i 行的数据只和第 i - 1 行有关,和本行无关,而我们知道 dp 数组在处理到第 i 行的时候 i - 1就已经处理好了,所以爱怎么遍历就怎么遍历。


5. 从二维数组到一维数组

上面我们使用二维数组对 dp 进行填充了,但是大家有没有注意到,第 i 行的结果只依赖第 i - 1 行,所以我们完全可以只使用一维数组,把 i 省略掉。相当于把 i 的结果粘贴到 i - 1行的位置,所以 dp[i] 就表示重量为 i 的容量能装入的最大物品价值是多少 ,大体过程如下:

  • 初始化 dp[0]
  • 根据 dp[0] 初始化 dp[1]

初始化 dp[0] 的时候,重量为 0 的背包肯定是放不下任何物品的,所以不需要初始化,下面看遍历逻辑。

public int findMax(int[] weight, int[] prices, int max){int[] dp = new int[max + 1];// 遍历物品for(int i = 0; i < weight.length; i++){// 遍历背包for(int j = max; j >= weight[i]; j--){dp[j] = Math.max(dp[j], dp[j - weight[i]] + prices[i]);}}return dp[max];
}

注意下 dp 公式为:

  • d p [ j ] = M a t h . m a x ( d p [ j ] , d p [ j − w e i g h t [ i ] ] + p r i c e s [ i ] ) dp[j] = Math.max(dp[j], dp[j - weight[i]] + prices[i]) dp[j]=Math.max(dp[j],dp[jweight[i]]+prices[i])

大家可能好奇为什么可以直接和 dp[j] 做比较,我把二维数组的 dp 粘贴过来。
在这里插入图片描述
dp 数组初始化为 0,当 i = 0 的时候,其实就是在初始化第一行 [0,15,15,15,15]当 i = 1 的时候,记住此时 dp 记录的是 i = 0 的结果,那么 dp[j] = Math.max(dp[j], dp[j - weight[i]] + prices[i]) 其实就是在根据 i = 0 来更新 i = 1 的数据,一直这样遍历下去,遍历到最后就是我们要的结果了


6. 一维数组的遍历次序

上面一维数组的遍历次序是先遍历物品,再遍历背包,那么可以先遍历背包,再遍历物品吗?也就是下面的写法。

// 遍历背包
for (int j = max; j >= 0; j--) {// 遍历物品for (int i = 0; i < weight.length; i++) {if (j >= weight[i]) {dp[j] = Math.max(dp[j], dp[j - weight[i]] + prices[i]);}}
}

让我们看下这个过程,当 j = 4 的时候,遍历所有物品,求 dp[j] 能放下的物品的最大价值,为什么我说求 dp[j] 的最大价值,因为是倒叙遍历,同时又是 j 在外层一直往前遍历,所以 dp[j - weight[i]] 你就当成 0 就好了,相当于 dp[j] = Math.max(dp[j], prices[i])

所以最终求出来的结果就是当前这个重量下能放下的物品的最大价值(单个)。

所以这里的遍历顺序就得是:先遍历物品,再遍历背包


7. 背包的遍历顺序

public int findMax(int[] weight, int[] prices, int max){int[] dp = new int[max + 1];// 遍历物品for(int i = 0; i < weight.length; i++){// 遍历背包for(int j = max; j >= weight[i]; j--){dp[j] = Math.max(dp[j], dp[j - weight[i]] + prices[i]);}}return dp[max];
}

继续回到遍历逻辑,注意到背包是从后往前遍历的,那么为什么不能从前往后遍历呢?

我们仔细看下 dp 的意义,由于从二维降到一维,我们在遍历的时候是不断用新获取的 dp[j] 覆盖原来的 dp[j],还是从二维数组的 dp 看下。
在这里插入图片描述
我上面说的意思相当于说,现在一维 dp 的数组是物品 0 所在的这行数据 [0,15,15,15,15]。当 i = 1 的时候,求出来的 20 会立马覆盖回数组,这时候数组是 [0,15,15,20,15],j = 3,继续往前遍历。

而如果缓存背包从前往后遍历,结果会是怎么样呢?我把物品的重量和价格粘贴过来。

重量价值
物品 0115
物品 1320
物品 2430

这次我们就看 i = 0 的遍历结果,初始化数组全是 0。
在这里插入图片描述

  • dp[0] = 0
  • dp[1] = Math.max(dp[1], dp[1-weight[0]] + prices[0]) = 15
  • dp[2] = Math.max(dp[2], dp[2-weight[0]] + prices[0]) = 30
  • dp[3] = Math.max(dp[3], dp[3-weight[0]] + prices[0]) = 45

最终结果就变成了:
在这里插入图片描述
其实出现这种情况,就是完全背包的做法了,也就是一个物品被选择了多个。

那么为什么会出现这种情况呢?其实我们还是可以从一维 dp 入手。

  • d p [ j ] = M a t h . m a x ( d p [ j ] , d p [ j − w e i g h t [ i ] ] + p r i c e s [ i ] ) dp[j] = Math.max(dp[j], dp[j - weight[i]] + prices[i]) dp[j]=Math.max(dp[j],dp[jweight[i]]+prices[i])

上面是一维的公式,假设现在数字组初始化为 0,那么在初始化 i = 0 的时候假设初始化了 dp[1] = 15,大家记住,这里的 dp 是实时覆盖的,所以这时候的状态如下:
在这里插入图片描述
这时候 dp[0] 和 dp[1] 都计算过了并且覆盖会原数组下标,而 dp[2]、dp[3]、dp[4] 还保留初始化的状态,啥意思呢,换成 i - 1 和 i,意思就是这时候 dp[0] 和 dp[1] 是 i = 1 计算出来的,而 dp[2]、dp[3]、dp[4] 则还是 dp[i-1] 的状态

我们接下来继续看 dp[2],我们知道 dp[2] = Math.max(dp[2], dp[1] + 15) = 30,意思就是在计算 dp[2] 的时候使用到了 dp[1],而这个 dp[1] 已经被覆盖过了,意思就是这个 dp[1] 不是 i - 1 的值了,而是 i 的值,所以就造成了多次选择。

在二维数组中计算 dp[i] 的时候是使用 dp[i-1] 的值,因为不会被覆盖,所以遍历顺序就无所谓。但是一维数组就不一样的,因为会实时覆盖,所以只能从后往前遍历,否则就会用前面已经计算过的值来计算当前下标的值了。


8. 代码总结

好了,到这里我们就解析完0-1背包了,分为二维和一维,其实说了这么多,大家只需要记住两个版本就行了。

public int findMaxD(int[] weight, int[] prices, int max){int[][] dp = new int[weight.length][max + 1];for(int j = 0; j <= max; j++){if(j >= weight[0]){dp[0][j] = prices[0];}}// 遍历物品for(int i = 1; i < weight.length; i++){// 遍历背包for(int j = 0; j <= max; j++){if(j < weight[i]){dp[i][j] = dp[i - 1][j];} else {dp[i][j] = Math.max(dp[i - 1][j], prices[i] + dp[i - 1][j - weight[i]]);}}}return dp[weight.length - 1][max];
}

一维的遍历如下:

public int findMax(int[] weight, int[] prices, int max){int[] dp = new int[max + 1];// 遍历物品for(int i = 0; i < weight.length; i++){// 遍历背包for(int j = max; j >= weight[i]; j--){dp[j] = Math.max(dp[j], dp[j - weight[i]] + prices[i]);}}return dp[max];
}

9. 总结

我们总结下二维数组和一维数组的遍历顺序:

  • 二维数组

    • 背包和物品的遍历顺序可以颠倒
    • 遍历背包的时候可以正序和倒叙遍历
  • 一维数组

    • 先遍历物品,再遍历背包
    • 遍历背包需要倒叙遍历





如有错误,欢迎指出!!!

相关文章:

【动态规划】详解 0-1背包问题

文章目录 1. 问题引入2. 从 dfs 到动态规划3. 动态规划过程分析4. 二维 dp 的遍历顺序5. 从二维数组到一维数组6. 一维数组的遍历次序7. 背包的遍历顺序8. 代码总结9. 总结 1. 问题引入 0-1 背包是比较经典的动态规划问题&#xff0c;这里以代码随想录里面的例子来介绍下。总的…...

【Java线程池与线程状态】线程池分类与最佳实践

解析Java线程池与线程状态变化&#xff0c;结合运行机制与业务场景对照&#xff0c;帮助形成系统性知识。 一、线程池核心要素&#xff08;五维模型&#xff09; 采用「参数配置→处理流程→工作模式」三层递进结构 核心参数&#xff08;线程池DNA&#xff09; corePoolSiz…...

【小白学AI系列】NLP 核心知识点(八)多头自注意力机制

文章目录 **多头自注意力机制&#xff08;Multi-Head Self-Attention&#xff09;****核心概念** **1. 自注意力机制&#xff08;Self-Attention&#xff09;****2. 多头机制&#xff08;Multi-Head Attention&#xff09;****3. 为什么要用多头注意力机制&#xff1f;****4. 公…...

学习笔记——word中图目录、表目录 标题引用

目标1&#xff1a; 建立——图1-1 引用——图1-1 1在word文档中的引用——>插入题注 新建标签&#xff0c;然后命名为“图1-“。 点击确认&#xff0c;即可插入如图所示 图1- 1 春天 需要把图1-和后面那个1中间的空格删除&#xff0c;即 图1-1 春天 2怎么去引用这个“…...

3.3 Hugging Face Transformers核心功能模块深度解析

Hugging Face Transformers核心功能模块深度解析 一、模块化架构总览 #mermaid-svg-wxTV5vrEo7Y57IlW {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-wxTV5vrEo7Y57IlW .error-icon{fill:#552222;}#mermaid-svg-wxT…...

linux中设置脚本定时执行ntp命令同步时间

目录 一、背景二、过程1.到系统目录2.安装ntp3.创建文件夹4.创建脚本文件5.提升脚本文件权限6.设置执行时间&#xff1a;7.检查是否设置了执行器&#xff08;执行后输出的内容为执行器中的定时执行内容&#xff09;8.执行脚本文件9.查看日志文件&#xff0c;是否执行成功 三、总…...

map的使用(c++)

在了解map之前&#xff0c;我们先看看两个场景&#xff0c;通过这两个场景的对比&#xff0c;让我们知道为什么要存在存储双关键字的容器 场景一&#xff1a;判断一堆字符串中&#xff0c;某一个字符串是否出现过 在没学set容器之前&#xff0c;我们只能想到把这一堆字符串存到…...

毕业设计—基于Spring Boot的社区居民健康管理平台的设计与实现

&#x1f393; 毕业设计大揭秘&#xff01;想要源码和文章&#xff1f;快来私信我吧&#xff01; Hey小伙伴们~ &#x1f44b; 毕业季又来啦&#xff01;是不是都在为毕业设计忙得团团转呢&#xff1f;&#x1f914; 别担心&#xff0c;我这里有个小小的福利要分享给你们哦&…...

Python:蟒蛇绘制(一笔画)

一、题目要求 使用turtle库&#xff0c;绘制一个蟒蛇形状的图形。‬ 二、代码展示 # 请在下方开始编写你的代码 import turtle turtle.setup(650,350,200,200) turtle.penup() turtle.fd(-250) turtle.pendown() turtle.pensize(25) turtle.pencolor("purple") turt…...

mysql查询判断函数,类似decode

mysql中没有decode函数&#xff0c;如果使用的话&#xff0c;会报如下错误&#xff1a;Error Code: 1305. FUNCTION stockdb.decode does not exist 如果要实现像 Oracle 数据库那样原生的 DECODE 函数&#xff0c;可以通过以下几种方式来实现类似 DECODE 函数的功能。 -- 创建…...

异常处理、事务管理

异常处理 程序开发过程中不可避免的会遇到异常现象 如何处理 方案一&#xff1a;在Controller的方法中进行try...catch处理&#xff08;代码臃肿&#xff0c;不推荐&#xff09; 方案二&#xff1a;全局异常处理器 全局异常处理器 RestControllerAdvice &#xff1a;定义全…...

UART(一)——UART基础

一、定义 UART(Universal Asynchronous Receiver/Transmitter)是一种广泛使用的串行通信协议,用于在设备间通过异步方式传输数据。它无需共享时钟信号,而是依赖双方预先约定的参数(如波特率)完成通信。 功能和特点 基本的 UART 系统只需三个信号即可提供稳健的中速全双工…...

MySQL 中各种日志简介

MySQL 日志 慢查询日志(Slow query log) 慢查询⽇志由执⾏时间超过系统变量 long_query_time 指定的秒数的SQL语句组成&#xff0c;并且检 查的⾏数⼤于系统变量 min_examined_row_limit 指定值。被记录的慢查询需要进⾏优化&#xff0c; 可以使⽤mysqldumpslow客⼾端程序对慢…...

【每日论文】Text-guided Sparse Voxel Pruning for Efficient 3D Visual Grounding

下载PDF或者阅读论文&#xff0c;请点击查看&#xff1a;LlamaFactory - huggingface daily paper - 每日论文解读 | LlamaFactory | LlamaFactory 摘要 中文 在这篇论文中&#xff0c;我们提出了一种高效的多级卷积架构&#xff0c;用于3D视觉定位。传统的由于采用两阶段或基…...

Kylin server v10部署docker

这里不用写什么标题 1. docker环境1.1 docker-ce1.1.1 yum安装1.1.2 离线安装 1.2 docker-compose 2. 镜像载入3. 服务启停4. 其他 1. docker环境 1.1 docker-ce docker-ce是社区版docker服务&#xff0c;可以通过yum方式直接安装或者离线安装&#xff0c;在国产化环境中&…...

计算机之就业主流岗(Mainstream Computer Employment Positions)

计算机之就业主流岗 计算机行业一直以来都是就业市场中的热门领域&#xff0c;技术岗位种类繁多&#xff0c;但每个岗位都有自己的核心技能和职责方向。以下是计算机行业中主流的技术岗位及其特点介绍&#xff0c;帮助你更清晰地了解这些职业的内容和发展前景。 1. 后端开发 …...

DeepSeek 助力 Vue 开发:打造丝滑的日期选择器(Date Picker),未使用第三方插件

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…...

【Mac技巧】添加DNS解析到hosts文件

【Mac技巧】添加DNS解析到hosts文件 Add DNS Resolution to hosts on Mac 我们通常访问一个Web站点&#xff08;即网址&#xff09;&#xff0c;需要输入网址关键字&#xff08;例如&#xff1a; 太平洋汽车网&#xff09;&#xff0c;或者输入pcauto.com.cn即可。 这期间仅…...

【批判性思维有什么用?】

1.批判性思维&#xff0c;指的是在人格平等的状态下&#xff0c;对自己和他人观点做谨慎多角度地思考。它讲究逻辑和理性&#xff0c;是一种高效地积累知识的方法。 2.只有那些我们完全不熟悉的结论和我们已经熟悉得不能再熟悉的结论&#xff0c;对它们的反思&#xff0c;才能…...

Golang学习笔记_34——组合模式

Golang学习笔记_31——原型模式 Golang学习笔记_32——适配器模式 Golang学习笔记_33——桥接模式 文章目录 一、核心概念1. 定义2. 解决的问题3. 核心角色4. 类图 二、特点分析三、适用场景1. 文件系统2. 图形界面3. 组织架构 四、代码示例&#xff08;Go语言&#xff09;五、…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...