本文目录

引言

题引

题目描述

输入

输出

样例输入

样例输出

解题过程

暴力求解

二维前缀和数组求解

[解读] 二维前缀和算法

本质

图解

代码表述

牛刀小试

题目描述

输入格式

输出格式

输入样例

输出样例

参考答案


引言

今天在学校oj平台做题时,有一道题目老是时间超限,后询问学长得知需要算法减少时间开销,于是习得了一个快速计算给定一个二维数组,求子数组的数组和,即二维前缀和。感叹算法的精妙,立即舍弃午睡,连忙赶来记录一下,给自己再温故一次。

题引

题目描述

C语言二维数组a[M][N], 给定四个整数LX,LY,RX,RY, 定义函数f(LX,LY,RX,RY)求数组若干元素之和:

输入

输入第一行是两个整数M和N, 表示二维数组a的大小, 0<M,N<=300。
随后有M行, 每行有N个整数,是数组a的数组元素值,值位于-1000到1000之间。
第M+2行是一个整数Q,表示有Q个查询
再随后有Q行,每行有四个空格分开的整数LX,LY,RX,RY。其中0<=LX<=RX<M, 0<=LY<=RY<N

60%的数据, M,N<=20, Q<=20
40%的数据, Q=100000

输出

总共输出Q行
对于每一行查询,输出f(LX,LY,RX,RY)的值。

样例输入

3 2
-1 -2
-3 -4
-5 -6
3
0 0 0 1
1 1 2 1
1 0 2 1

样例输出 

-3
-10
-18

解题过程

像我这种毫无基础的小白,就只会先想到翻译题目意思,循环暴力求解。于是乎就有了:

暴力求解

#include<stdio.h>
int main(void)
{int n, i, j, k;scanf("%d %d", &n,&k);int w, lx, ly, rx, ry;int a[301][301];for (i = 0; i < n; i++) {for (j = 0; j < k; j++) {scanf("%d", &a[i][j]);}}scanf("%d", &w);for (int z = 0; z < w; z++) {int sum = 0;scanf("%d %d %d %d", &lx, &ly, &rx, &ry);for (int q = lx; q <= rx; q++) {for (int p = ly; p <= ry; p++) {sum = sum + a[q][p];}}printf("%d\n", sum);}//LX,LY,RX,RY。其中0<=LX<=RX<M, 0<=LY<=RY<Nreturn 0;
}

评判机显然不买账,直接以“时间超限”为由把我编译的代码打回了。

二维前缀和数组求解

在我询问班上acm队大佬时,我得到了她的一句话:“二维数组前缀和,又称矩阵和,搜一下这个算法,这道题用算法写”。

我在网上找了很久以及询问其他学长,终于搞懂了什么叫“二维数组前缀和”。于是乎经过一番捣腾,终于让测评姬收下我的代码,代码如下:

#include<stdio.h>
int main(void)
{int n, i, j, k;scanf("%d %d", &n,&k);int w, lx, ly, rx, ry;int a[301][301];int sum[301][301];for (i = 1; i <= n; i++) {for (j = 1; j <= k; j++) {scanf("%d", &a[i][j]);sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + a[i][j];}}scanf("%d", &w);for (int z = 0; z < w; z++) {int re = 0;scanf("%d %d %d %d", &lx, &ly, &rx, &ry);/*for (int q = lx; q <= rx; q++) {for (int p = ly; p <= ry; p++) {sum = sum + a[q][p];}}*/lx++; ly++; rx++; ry++;re = sum[rx][ry] - sum[rx][ly-1] - sum[lx-1][ry] + sum[lx-1][ly-1];printf("%d\n", re);}//LX,LY,RX,RY。其中0<=LX<=RX<M, 0<=LY<=RY<Nreturn 0;
}

这里就只增加二维前缀和数组sum。

看不懂?正常!别着急,且听我细细道来!

接下来我将从是什么,怎么来,怎么用三个角度来介绍二维前缀和算法。

[解读] 二维前缀和算法

本质

二维前缀和实际上就是一个矩阵内值的和,而矩阵又可以由两个行数或列数少一的子矩阵组合后,删去重合部分再加上右下角的值共四个部分来构成。

话不多说,直接上图理解:

图解

还没有理解吗?那在来看看这个例子 原二维数组a 与 二维前缀和数组S 之间的关系:

这样的好处是: 大大减少了原先通过两层for循环计算子数组所耗费的时间,只需要在插入数据时,对应的计算出二维前缀和数组,计算子矩阵的元素之和时不需要双层遍历,直接通过公式计算而的,这极大的减少了时间复杂度。

代码表述

其更一般的算法表述如下:(代码源于网络)

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1010;int a[N][N], s[N][N];
int n, m, q;
int main()
{cin >> n >> m;for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++)cin >> a[i][j];for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++)s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + a[i][j];cin >> q;while (q--){int x1, y1, x2, y2;cin >> x1 >> y1 >> x2 >> y2;cout << s[x2][y2] - s[x2][y1-1] - s[x1-1][y2] + s[x1-1][y1-1] << endl;}return 0;
}

牛刀小试

Ok,是不是觉得不过瘾?来试试这一个类似简单的题目吧!

题目描述

输入一个 n 行 m 列的整数矩阵,再输入 q 个询问,每个询问包含四个整数 x1,y1,x2,y2,表示一个子矩阵的左上角坐标和右下角坐标。对于每个询问输出子矩阵中所有数的和。

输入格式

第一行包含三个整数 n,m,q。

接下来 n 行,每行包含 m 个整数,表示整数矩阵。
接下来 q 行,每行包含四个整数 x1,y1,x2,y2,表示一组询问。

输出格式

共 q 行,每行输出一个询问的结果。

输入样例

3 4 3
1 7 2 4
 3 6 2 8
2 1 2 3
1 1 2 2
2 1 3 4
1 3 3 4

输出样例

17
27
21


参考答案

#include<iostream>
using namespace std;const int N = 1010;int n, m;
int q;
int a[N][N], s[N][N];
int main()
{scanf("%d%d%d", &n, &m, &q);for(int i = 1; i <= n; i ++){for(int j = 1; j <= m; j ++){scanf("%d", &a[i][j]);}}for(int i = 1; i <= n; i ++){for(int j = 1; j <= m; j ++){s[i][j] = s[i][j-1] + s[i-1][j] - s[i-1][j-1] + a[i][j];}}while(q --){int x1, y1, x2, y2;scanf("%d%d%d%d", &x1, &y1, &x2, &y2);printf("%d\n", s[x2][y2] - s[x2][y1-1] - s[x1-1][y2] + s[x1-1][y1-1]);}return 0;
}

OK以上就是本文的所有内容了,如有错误欢迎指出讨论!

[算法]二维数组前缀和相关推荐

  1. 前缀和——(2)二维数组前缀和

    前面部分我们介绍了一维前缀和https://blog.csdn.net/justidle/article/details/103524440.下面我们扩展一下,来介绍二维前缀和. 什么是二维前缀和 比 ...

  2. 算法——二维数组回形打印

    问题: 对二维数组进行回形(蛇形)打印 代码: package com.ziling.mianshi;/*** @Author: yipeng* @Date: 2021/7/27 17:43*/ pu ...

  3. 矩阵行列互换算法-二维数组

    矩阵行列互换算法的实例要从一个简单的例子来归纳 [1,2,3] [4,5,6] [7,8,9] --由---到-----> [1,4,7] [2,5,8] [3,6,9] 由上面的单行到下面的单 ...

  4. wireless(二维数组前缀和)

    1 . 无线网络发射器选址 (wireless.cpp/c/pas) [问题描述] 随着智能手机的日益普及,人们对无线网的需求日益增大.某城市决定对城市内的公共 场所覆盖无线网. 假设该城市的布局为由 ...

  5. 前缀和(一维数组+二维数组+差分)

    前缀和与差分 图文并茂 超详细整理(全网最通俗易懂)_林深不见鹿 的博客-CSDN博客_前缀和与差分 讲得非常的好,大幅度降低时间复杂度 特别是二维数组的前缀和 二维数组前缀和例题,利用二维数组的前缀 ...

  6. php查找二维数组下标,PHP实现二维数组中的查找算法小结

    本文实例讲述了PHP实现二维数组中的查找算法.分享给大家供大家参考,具体如下: 方法1:silu从左下角最后一行的第一个元素开始,遍历.如果小于target 则遍历该行的所有元素,找到结束.如果大于继 ...

  7. c语言暴力求解法二维数组比较,【算法】搜索二维矩阵 暴力解法二分法 4种语言...

    编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值.该矩阵具有如下特性: 每行中的整数从左到右按升序排列. 每行的第一个整数大于前一行的最后一个整数. 示例 1:输入:matrix = ...

  8. 求马鞍点java_二维数组马鞍点求解算法

    若在矩阵A 中存在一个元素ai,j(0≤i≤n-1,0≤j≤m-1),该元素是第i行元素中最小值且又是第j 列元素中最大值,则称此元素为该矩阵的一个马鞍点.假设以二维数组存储矩阵A,试设计一个求该矩阵 ...

  9. php二维数组中的查找,PHP实现二维数组中的查找算法小结

    本文实例讲述了PHP实现二维数组中的查找算法.分享给大家供大家参考,具体如下: 方法1:silu从左下角最后一行的第一个元素开始,遍历.如果小于target 则遍历该行的所有元素,找到结束.如果大于继 ...

最新文章

  1. c# 之 URL资源访问
  2. 北大清华“合并开班”:AI大牛朱松纯带队,面向元培和自动化系招生
  3. 006-1MOS管工作原理精讲
  4. [博客之路]如何增加一个博客的PR值(一)
  5. Python 模块之科学计算 Pandas
  6. ios时间相差多少天_iOS 计算某个时间到现在是多少月/天/时
  7. java web 定制化界面_实现javaWeb网页自定义出错界面
  8. 计算力就是你的核心业务!
  9. 2017-2018-1 20155301 20155307 20155339 《信息安全系统设计基础》 实验一 开发环境的熟悉...
  10. [USACO09FEB]改造路Revamping Trails 分层最短路 Dijkstra BZOJ 1579
  11. web.config中特殊字符的处理
  12. 计算机图形学_GAMES101-现代计算机图形学课程 全笔记
  13. 协议(Protocol)类比java中的interface
  14. Echarts 模拟飞机飞行动态图
  15. echart水滴_echart 水滴图
  16. 解析:Python就业方向有哪些?
  17. MongoDB 使用Index
  18. 2021-08-05 得帆技术培训Linux作业
  19. 前端复习之JavaScript(ECMAScript5)
  20. Java参数变量_Java变量参数

热门文章

  1. 20世纪最伟大的数学家之一弗拉基米尔·阿诺德
  2. 阿里云轻量应用服务器无法远程访问
  3. Markdown语言基础使用教程
  4. An Easy DVD Ripper
  5. 大数据采集的流程是什么,主要分为哪几步?
  6. win10电脑鼠标灵敏度怎么设置 win10电脑鼠标灵敏度设置的方法
  7. c语言和线性代数哪个难,学编程数学到底有多重要?线性代数能否视为一门程序语言呢?...
  8. 2014互联网IT待遇
  9. AVProVideo☀️一、一款U3D视频播放插件介绍
  10. 千聊资费说明和提现须知