算法刷题笔记 差分矩阵(C++实现)

文章目录

    • 题目前言
    • 题目描述
    • 解题思路和代码实现

题目前言

这道题是一道差分算法的拓展题型,是算法刷题笔记到目前为止我认为最困难的题目之一。因此,这篇题解博客的过程记录也最为详细,希望能够为你带来帮助。

题目描述

  • 输入一个nm列的整数矩阵,再输入q个操作,每个操作包含五个整数 x1,y1,x2,y2,c,其中 (x1,y1)(x2,y2)表示一个子矩阵的左上角坐标和右下角坐标。
  • 每个操作都要将选中的子矩阵中的每个元素的值加上c
  • 请你将进行完所有操作后的矩阵输出。

输入格式

  • 第一行包含整数n,m,q
  • 接下来n行,每行包含m个整数,表示整数矩阵。
  • 接下来q行,每行包含5个整数x1,y1,x2,y2,c,表示一个操作。

输出格式

  • n行,每行m个整数,表示所有操作进行完毕后的最终矩阵。

数据范围

  • 1 ≤ n,m ≤ 1000,
  • 1 ≤ q ≤ 100000,
  • 1≤x1≤x2≤n,
  • 1≤y1≤y2≤m,
  • −1000≤c≤1000,
  • −1000≤矩阵内元素的值≤1000

解题思路和代码实现

完整的C++解题代码如下所示:

#include <cstdio>const int N(1010);
int matrix[N][N];
int dif_matrix[N][N]; // C++中整数类型的二维数组中的所有元素都会被初始化为0//用于逐步构建差分矩阵的函数
inline void insert_to_matrix(const int& x1, const int& y1, const int& x2, const int& y2, const int& c)
{dif_matrix[x1][y1] += c;dif_matrix[x1][y2 + 1] -= c;dif_matrix[x2 + 1][y1] -= c;dif_matrix[x2 + 1][y2 + 1] += c;
}int main(void)
{// 变量定义int n, m, q;// 变量输入scanf("%d %d %d", &n, &m, &q);// 根据输入构造差分矩阵(行列下标都从1开始,更加方便)for(int i(1); i <= n; ++i){for(int j(1); j <= m; ++j){int x;scanf("%d", &matrix[i][j]);insert_to_matrix(i, j, i, j, matrix[i][j]);}}// 构造差分矩阵for(int i(0); i < q; ++i){int x1, y1, x2, y2, c;scanf("%d %d %d %d %d", &x1, &y1, &x2, &y2, &c);insert_to_matrix(x1, y1, x2, y2, c);}// 差分矩阵构造完成,根据差分矩阵递推出原矩阵并输出for(int i(1); i <= n; ++i){for(int j(1); j <= m; ++j){dif_matrix[i][j] += (dif_matrix[i - 1][j] + dif_matrix[i][j - 1] - dif_matrix[i - 1][j - 1]);printf("%d ", dif_matrix[i][j]);}printf("\n");}
}

下面将对代码进行逐部分讲解。

第一部分

#include <cstdio>const int N(1010);
int matrix[N][N];
int dif_matrix[N][N]; // C++中整数类型的二维数组中的所有元素都会被初始化为0
  • 首先,代码中导入了头文件cstdio,因为需要使用其中的scanf函数和printf函数分别进行变量的输入和结果的输出。之所以使用这两个C语言中的输入输出函数而不是C++中的cincout对象,是因为本题中的输入输出都涉及矩阵,数据量较大,使用这两个函数的效率远高于使用cincout
  • 定义了大小为1010的整数常量,这是因为根据题目中的数据范围,矩阵的行和列都不会超过1000,而为了防止编程过程中二维数组的访问越界,用一个比1000稍大的数字更好,此处选用1010,用于表示二维数组的最大行数和列数。这个二维数组在所有函数之外进行声明和创建,因此是一个静态数组。静态数组中所有元素都会被默认初始化为0,这就方便了我们后续对该数组的使用。
  • 这里的matrix是指原始矩阵,即用户输入的值构成的矩阵;dif_matrix即为差分矩阵。

第二部分

int main(void)
{// 变量定义int n, m, q;// 变量输入scanf("%d %d %d", &n, &m, &q);// 根据输入构造差分矩阵(行列下标都从1开始,更加方便)for(int i(1); i <= n; ++i){for(int j(1); j <= m; ++j){int x;scanf("%d", &matrix[i][j]);insert_to_matrix(i, j, i, j, matrix[i][j]);}}
  • 这一部分首先使用比cin效率更高的scanf函数读入三个变量,然后根据用户的输入给二维数组中的指定位置插入元素,创建一个模拟的矩阵。
  • 需要注意的是,此处我们没有将数组的下标从0开始使用,而是从1开始使用,这是因为用户在后续查询过程中都是输入的数组的行号和列号,两者都不为零,此处将下标从1开始便于和后面的过程保持一致。
  • 用户每使用scanf函数输入一个矩阵元素,程序都会使用insert_to_matrix函数来根据该元素的值修改差分矩阵中的内容(起初差分矩阵中的值都是0),这个函数的详细解释请看下面的第三部分。此处将插入的坐标设置为一个单元格。
  • 执行完这一部分后,就得到了和原始矩阵相对应的差分矩阵。所以可以看出,并没有一个直接的函数,将原始矩阵转换为差分矩阵,差分矩阵是根据原矩阵和差分矩阵中对应位置的元素之间的关系来一步一步构造的。

第三部分

//用于逐步构建差分矩阵的函数
inline void insert_to_matrix(const int& x1, const int& y1, const int& x2, const int& y2, const int& c)
{dif_matrix[x1][y1] += c;dif_matrix[x1][y2 + 1] -= c;dif_matrix[x2 + 1][y1] -= c;dif_matrix[x2 + 1][y2 + 1] += c;
}
  • 将该函数定义为内联函数,是因为函数中不包含循环和复杂的分支语句,并且函数操作量很少,所以定义为inline内联函数有可能可以提高执行效率。
  • 函数参数列表使用常引用进行传参,也有可能提高传参效率。
  • 该函数用于修改差分矩阵中的值,使得指定的子矩阵中的元素都能满足加上一个常数c,即传入的最后一个参数。具体的公式推导略,可以通过简答的画图理解公式的内容。

第四部分

// 构造差分矩阵for(int i(0); i < q; ++i){int x1, y1, x2, y2, c;scanf("%d %d %d %d %d", &x1, &y1, &x2, &y2, &c);insert_to_matrix(x1, y1, x2, y2, c);}
  • 这一部分根据用户的指定将原始矩阵中的多个子矩阵统一增加一个值,可以通过前面第三部分的函数修改差分矩阵中的四个值进行实现。这样,只需要修改四个值即完成一次修改,而不需要通过双重循环的方式,逐个给子矩阵中的元素加上一个值。

第五部分

// 差分矩阵构造完成,根据差分矩阵递推出原矩阵并输出for(int i(1); i <= n; ++i){for(int j(1); j <= m; ++j){dif_matrix[i][j] += (dif_matrix[i - 1][j] + dif_matrix[i][j - 1] - dif_matrix[i - 1][j - 1]);printf("%d ", dif_matrix[i][j]);}printf("\n");}
  • 根据差分矩阵中的值,只需要一步公式运算即可确定修改后的原始矩阵中的值,公式如上,推导过程可以参考 算法刷题笔记 子矩阵的和(C++实现)。
  • 每输出一行矩阵元素都要记得换一行,即输出一个换行符\n

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

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

相关文章

JavaScript的垃圾回收机制

No.内容链接1Openlayers 【入门教程】 - 【源代码示例300】 2Leaflet 【入门教程】 - 【源代码图文示例 150】 3Cesium 【入门教程】 - 【源代码图文示例200】 4MapboxGL【入门教程】 - 【源代码图文示例150】 5前端就业宝典 【面试题详细答案 1000】 文章目录 一、垃圾…

匹配字符串

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 Python提供了re模块&#xff0c;用于实现正则表达式的操作。在实现时&#xff0c;可以使用re模块提供的方法&#xff08;如search()、match()、finda…

深入理解Redis:多种操作方式详解

Redis&#xff08;Remote Dictionary Server&#xff09;是一款高性能的开源键值存储系统&#xff0c;广泛应用于缓存、会话管理、实时分析等领域。它支持多种数据结构&#xff0c;如字符串、哈希、列表、集合和有序集合等&#xff0c;提供了丰富的操作命令。本篇博客将详细介绍…

信息系统项目管理师0603:项目整合管理 — 考点总结(可直接理解记忆)

点击查看专栏目录 文章目录 项目整合管理 — 考点总结(可直接理解记忆) 输入、输出、工具和技术 历年考题直接考输入,输出、工具和技术的有17年11月第34、35,19年5月第34、35,20年11月27、28,21年5月第26,28,21年11月第28,22年5月第25,22年11月第22考题 项目章程是正…

CasaOS玩客云安装全平台高速下载器Gopeed并实现远程访问

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

BufferQueue 的工作原理

bufferQueue 是 Android 图形栈中的一个核心组件,它在生产者和消费者之间传递缓冲区(buffer)。它通常用于图形缓冲区管理,特别是在 SurfaceFlinger 和其他图形相关的组件中。理解 BufferQueue 的工作原理对开发高性能图形应用和解决图形渲染问题非常有帮助。 BufferQueue …

基于Python的酒店客房入侵检测系统的设计与实现

基于Python的酒店客房入侵检测系统的设计与实现 开发语言:Python 数据库&#xff1a;MySQL所用到的知识&#xff1a;Django框架工具&#xff1a;pycharm、Navicat、Maven 系统功能实现 酒店客房入侵管理界面 结合上文的结构搭建和用户需求&#xff0c;酒店客房入侵检测系统的…

【Unity Shader入门精要 第12章】屏幕后处理效果(一)

1. 原理和过程 屏幕后处理是绑定摄像机的&#xff0c;通过抓取当前摄像机渲染的图像作为 SrcTextrue&#xff0c;然后按需依次调用处理接口&#xff0c;对 SrcTexture 进行处理&#xff0c;最后将处理完成的 DstTexture 显示到屏幕上&#xff0c;整个过程的调度通过 C# 脚本完…

使用 C++ 在当前进程中获取指定模块的基址

C 实现 , 获取指定模块在该进程中的基址 1、流程: 获取进程的所有模块信息–>遍历模块列表 2、实现&#xff1a; // 我自己定义的 typedef struct moudle_date_ {HANDLE mhandle; // 句柄char mname[64]; // 名称char* date; // 数据DWORD mdword; // 基址…

【机器学习】Adaboost: 强化弱学习器的自适应提升方法

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 Adaboost: 强化弱学习器的自适应提升方法引言Adaboost基础概念弱学习器与强学习…

存储器容量小才使用SRAM芯片,容量较大时使用DRAM芯片。为什么?

在计算机系统中&#xff0c;存储器容量的选择涉及到多种因素&#xff0c;包括成本、速度和复杂性。SRAM&#xff08;静态随机存取存储器&#xff09;和DRAM&#xff08;动态随机存取存储器&#xff09;是两种常见的内存类型&#xff0c;它们在设计和应用上有显著的不同。以下是…

【蓝桥杯嵌入式】 第六届国赛

目录 题目 配置 注意事项 代码 - 默写大师 EEPROM读写函数 LED驱动函数 ADC采集 上电初始化 LCD 按键 PWM互补输出 全部代码 hardware.c hardware.h control.c control.h main.c 题目 配置 注意事项 复制LCD的工程&#xff0c;先配置资源 --- 勾选完选项一…

CCIG 2024:合合信息文档解析技术突破与应用前景

目录 背景当前大模型训练和应用面临的问题训练Token耗尽训练语料质量要求高LLM文档问答应用中文档解析不精准 合合信息的文档解析技术1. 具备多文档元素识别能力2. 具备版面分析能力3. 高性能的文档解析4. 高精准、高效率的文档解析文档多板式部分示例 文档解析典型技术难点元素…

【代码随想录Day23】|669.修建二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树

669. 修剪二叉搜索树 这题最开始的想法是复用删除节点的那题的思路做&#xff0c;需要修改的部分就是要让程序删除完一个点后继续遍历&#xff0c;因为后续可能还有不符合条件的节点。但这样想也做复杂了。 这类题其实不用想用什么序遍历&#xff0c;用哪种方式只是为了更好的…

案例|开发一个美业小程序,都有什么功能

随着移动互联网的迅猛发展&#xff0c;美业连锁机构纷纷寻求数字化转型&#xff0c;以小程序为载体&#xff0c;提升服务效率&#xff0c;增强客户体验。 线下店现在面临的困境&#xff1a; 客户到店排队时间过长&#xff0c;体验感受差 新客引流难&#xff0c;老用户回头客…

基于EV54Y39A PIC-IOT WA的手指数量检测功能开发(MPLAB+ADC)

目录 项目介绍硬件介绍项目设计开发环境及工程参考总体流程图硬件基本配置光照传感器读取定时器检测逻辑 功能展示项目总结 &#x1f449; 【Funpack3-2】基于EV54Y39A PIC-IOT WA的手指数量检测功能开发 &#x1f449; Github: EmbeddedCamerata/PIC-IOT_finger_recognition 项…

Flutter基础 -- Dart 语言 -- 注释函数表达式

目录 1. 注释 1.1 单行注释 1.2 多行注释 1.3 文档注释 2. 函数 2.1 定义 2.2 可选参数 2.3 可选参数 默认值 2.4 命名参数 默认值 2.5 函数内定义 2.6 Funcation 返回函数对象 2.7 匿名函数 2.8 作用域 3. 操作符 3.1 操作符表 3.2 算术操作符 3.3 相等相关的…

上海亚商投顾:沪指冲高回落 两市成交金额仅剩7000亿

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 三大指数昨日冲高回落&#xff0c;午后一度集体翻绿&#xff0c;临近尾盘小幅回升。光伏产业链再度走强&#…

aws 在ecs外部实例上运行gpu负载

参考资料 https://docs.amazonaws.cn/zh_cn/AmazonECS/latest/developerguide/ecs-gpu.htmlhttps://docs.amazonaws.cn/AWSEC2/latest/UserGuide/accelerated-computing-instances.html#gpu-instanceshttps://docs.amazonaws.cn/AWSEC2/latest/UserGuide/install-nvidia-drive…

LeetCode 63.不同路径Ⅱ

思路&#xff1a; 在有障碍物的地方增加一个判断即可 class Solution { public:int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {int dp[105][105];int mobstacleGrid.size();int nobstacleGrid[0].size();for(int i0;i<m;i){for(int j0…