我们考虑一个$N\times M$的矩阵数据,若要对矩阵中的部分数据进行读取,比如求某个$a\times b$的子矩阵的元素和,通常我们可以想到$O(ab)$的遍历那个子矩阵,对它的各个元素进行求和。然而当$a$或$b$很大的时候,这样的计算显得太慢,如果要求子矩阵的最大元素和(如Ural 1146),更是简直慢到不能忍。

        于是就想,能不能在读入数据的同时,我就先进行一些预处理,使得到后面进行计算的时候,可以简化一些步骤呢?答案是可以的。
        我们开一个二维数组存放矩阵,第$0$行和第$0$列全都置$0$,真正的矩阵在数组中下标从$1$开始。
        通常对矩阵有两种预处理:
        一种是把矩阵拍扁,即把前一列或前一行加到后一列或后一行上:
按列压缩↑,紫色部分和=棕色部分和-橙色部分和
按行压缩↑,紫色部分和=棕色部分和-橙色部分和
        以按行压缩为例,读入当前元素$t=A_{ij}$后,我们令$B_{ij}=A_{ij}+B_{i-1,j}$,以此类推,当所有数据读入后,预处理即完成,$B_{ij}$表示对于矩阵$A$的第$j$列,从第1行到第$i$行的和。这样我们若想要知道矩阵$A$第$j$列上,从第$p$行到第$q$行的和,直接用$B_{qj}-B_{p-1,j}, (p\leq q)$一步求出,而不需要进行$q-p+1$步计算,那么从左上角$A_{ab}$到右下角$A_{pq}$的子矩阵元素和为$sum$$=$$\sum\limits_{i=a}^{p}\sum\limits_{j=b}^{q}$$A_{ij}$$=$$\sum\limits_{j=b}^{q}$$B_{pj}$$-$$\sum\limits_{j=b}^{q}$$B_{a-1,j}$大大减少了计算量,降低了时间复杂度。
        比较丑的示例代码:
 #include <stdio.h>
const int N=;
int matA[N][N], matB[N][N];
int main()
{
puts("Please input a matrix:");
for(int i=; i<N; i++)
for(int j=; j<N; j++) {
scanf("%d", matA[i]+j);
matB[i][j]=matB[i-][j]+matA[i][j];
}
puts("The Preprocessed matrix is:");
for(int i=; i<N; i++)
for(int j=; j<N; j++)
printf("%d%c", matB[i][j], j==N-?'\n':' '); int a, b, p, q, res;
while(puts("Please input a, b and p, q:"),
~scanf("%d%d%d%d", &a, &b, &p, &q) )
{
res=;
puts("Sum from A_ab to A_pq is:");
for(int j=b; j<=q; j++)
res+=matB[p][j]-matB[a-][j];
printf("%d\n\n", res);
}
return ;
}
        运行结果:
 
       而另一种则是压缩到一个元素上,用$B_{ij}$表示从最左上角元素$A_{11}$到元素$A_{ij}$的和$\sum\limits_{m=1}^{i}\sum\limits_{n=1}^{j}$$A_{mn}$$, $$(i \geq 1, j \geq 1)$:
读入预处理↑,右图紫色块=4+24+30-18=40
        为了保持这一性质,我们在读入当前元素$t=A_{ij}$后,令$B_{ij}$$=$$A_{ij}$$+$$B_{i,j-1}$$+$$B_{i-1,j}$$-$$B_{i-1,j-1}$。当所有数据读入后,预处理即完成。
计算区域和↑,紫色区域和=60-12-15+3=36
        此时我们若想要求出从左上角$A_{ab}$到右下角$A_{pq}$的子矩阵元素和,只需三步计算:$sum$$=$$\sum\limits_{i=a}^{p}\sum\limits_{j=b}^{q}$$A_{ij}$$=$$B_{pq}$$-$$B_{p,b-1}$$-$$B_{a-1,q}$$+$$B_{a-1,b-1}$,即可使时间复杂度降低到常数。
        比较丑的示例代码:
 #include <stdio.h>
const int N=;
int matA[N][N], matB[N][N];
int main()
{
puts("Please input a matrix:");
for(int i=; i<N; i++)
for(int j=; j<N; j++) {
scanf("%d", matA[i]+j);
matB[i][j]=matA[i][j]+matB[i][j-]+matB[i-][j]-matB[i-][j-];
}
puts("The Preprocessed matrix is:");
for(int i=; i<N; i++)
for(int j=; j<N; j++)
printf("%3d%c", matB[i][j], j==N-?'\n':' '); int a, b, p, q, res;
while(puts("Please input a, b and p, q:"),
~scanf("%d%d%d%d", &a, &b, &p, &q) )
{
puts("Sum from A_ab to A_pq is:");
res=matB[p][q]-matB[p][b-]-matB[a-][q]+matB[a-][b-];
printf("%d\n\n", res);
}
return ;
}
        运行结果:

ACM 中 矩阵数据的预处理 && 求子矩阵元素和问题的更多相关文章

  1. 矩阵快速幂在ACM中的应用

    矩阵快速幂在ACM中的应用 16计算机2黄睿博 首发于个人博客http://www.cnblogs.com/BobHuang/ 作为一个acmer,矩阵在这个算法竞赛中还是蛮多的,一个优秀的算法可以影 ...

  2. 市场清仓价格算法 python求矩阵不同行不同列元素和的最大值

    问题描述 求矩阵不同行不同列元素和的最大值(最小值) 问题求解 1.通过scipy库求解 scipy.optimize库中的linear_sum_assignment方法可以求解 输入一个矩阵,参数m ...

  3. 关于 矩阵在ACM中的应用

    关于矩阵在ACM中的应用 1.矩阵运算法则 重点说说矩阵与矩阵的乘法,不说加减法. 支持: 结合律  (AB)C = A(BC) 分配律 A(B+C) = AB + AB $\left( \lambd ...

  4. Matlab中矩阵的平方和矩阵中每个元素的平方介绍

    该文章讲述了Matlab中矩阵的平方和矩阵中每个元素的平方介绍.   设t = [2 4 2 4] 则>> t.^2 ans = 4 164 16 而>> t^2 ans = ...

  5. C语言:将ss所指字符串中所有下标为奇数位置的字母转换为大写-将该字符串中的所有字符按ASCII码值升序排序后输出。-将a所指的4*3矩阵第k行的元素与第0行元素交换。

    //函数fun:将ss所指字符串中所有下标为奇数位置的字母转换为大写,若不是字母,则不转换. #include<conio.h> #include<stdio.h> #incl ...

  6. matlab中矩阵的表示与简单操作

    原文地址为:matlab矩阵的表示和简单操作 一.矩阵的表示在MATLAB中创建矩阵有以下规则: a.矩阵元素必须在”[ ]”内: b.矩阵的同行元素之间用空格(或”,”)隔开: c.矩阵的行与行之间 ...

  7. Java在ACM中的应用

    Java在ACM中的应用 —. 在java中的基本头文件(java中叫包) import java.io.*; import java.util.*; //输入Scanner import java. ...

  8. stl 在 acm中的应用总结

    总结一些在acm中常用的小技巧,小函数 之前尝试着总结过很多次.都失败了,因为总是担心不全,理解的也不是很透彻.这次再来一次...其实之前保存了很多的草稿就不发布了,当然,下面说的很不全面,路过的大牛 ...

  9. Python numpy中矩阵的用法总结

    关于Python Numpy库基础知识请参考博文:https://www.cnblogs.com/wj-1314/p/9722794.html Python矩阵的基本用法 mat()函数将目标数据的类 ...

随机推荐

  1. 【Win 10应用开发】分阶段进行数据绑定

    使用x:Bind扩展标记进行数据绑定,是在编译阶段完成,至于说性能优化方面,大概主要是优化CPU资源的使用,因为免去了运行阶段进行绑定的过程.当然,使用这个标记仅仅是绑定上的优化,并不包括数据源.数据 ...

  2. 利用select实现IO多路复用TCP服务端

    一.相关函数 1.  int select(int maxfdp, fd_set *readset, fd_set *writeset, fd_set *exceptset,struct timeva ...

  3. call,apply,bind的用法

    关于call,apply,bind这三个函数的用法,是学习javascript这门语言无法越过的知识点.下边我就来好好总结一下它们三者各自的用法,及常见的应用场景. 首先看call这个函数,可以理解成 ...

  4. Java 二叉树遍历右视图-LeetCode199

    题目如下: 题目给出的例子不太好,容易让人误解成不断顺着右节点访问就好了,但是题目意思并不是这样. 换成通俗的意思:按层遍历二叉树,输出每层的最右端结点. 这就明白时一道二叉树层序遍历的问题,用一个队 ...

  5. SparkStreaming实现Exactly-Once语义

    作者:Syn良子 出处:http://www.cnblogs.com/cssdongl 转载请注明出处 译自:http://blog.cloudera.com/blog/2015/03/exactly ...

  6. AngularJs学习笔记(制作留言板)

    原文地址:http://www.jmingzi.cn/?post=13 初学Anjularjs两天了,一边学一边写的留言板,只有一级回复嵌套.演示地址 这里总结一下学习的过程和笔记.另外,看看这篇文章 ...

  7. 我是如何进行Spring MVC文档翻译项目的环境搭建、项目管理及自动化构建工作的

    感兴趣的同学可以关注这个翻译项目 . 我的博客原文 和 我的Github 前段时间翻译的Spring MVC官方文档完成了第一稿,相关的文章和仓库可以点击以下链接.这篇文章,主要是总结一下这个翻译项目 ...

  8. 用JWT来保护我们的ASP.NET Core Web API

    在上一篇博客中,自己动手写了一个Middleware来处理API的授权验证,现在就采用另外一种方式来处理这个授权验证的问题,毕竟现在也 有不少开源的东西可以用,今天用的是JWT. 什么是JWT呢?JW ...

  9. 【转】基于.NET平台常用的框架整理

    自从学习.NET以来,优雅的编程风格,极度简单的可扩展性,足够强大开发工具,极小的学习曲线,让我对这个平台产生了浓厚的兴趣,在工作和学习中也积累 了一些开源的组件,就目前想到的先整理于此,如果再想到, ...

  10. C#开发微信门户及应用(13)-使用地理位置扩展相关应用

    本文继续上一篇<C#开发微信门户及应用(12)-使用语音处理>,继续介绍微信的相关应用.我们知道,地理位置信息可以用来做很多相关的应用,除了我们可以知道用户所在的位置,还可以关联出一些地理 ...