• 矩阵求和


    矩阵求和

    难度级别:A; 编程语言:不限;运行时间限制:3000ms; 运行空间限制:256000KB; 代码长度限制:2000000B

    试题描述

    矩阵求和

    输入

    第一行n和m,表示行数和列数
    接下来n行表示矩阵
    再来一行一个整数q,表示询问个数
    接下来q行,每行四个整数x1,y1,x2,y2表示左上右下的坐标

    输出

    对于每个询问输出一个整数表示该矩阵范围内的整数和

    输入示例

    5 5
    1 2 5 4 1
    1 1 7 6 8
    8 7 9 5 2
    4 4 4 1 8
    5 10 11 13 7
    3
    2 1 4 3
    2 2 5 5
    4 1 5 4

    输出示例

    45
    103
    52

    其他说明

    n,m < 2001
    q < 100001
    矩阵内所有数小于2000

    代码:

     1 #include<iostream>
     2 
     3 int a,m,n,i,j,k,x1,y1,x2,y2;
     4 
     5 long long sum,s[2002][2002]={0};//数组s用来储存前缀和
     6 
     7 using namespace std;
     8 
     9 int main()
    10 
    11 {
    12 
    13             scanf("%d%d",&m,&n);
    14 
    15 for(i=1;i<=m;i++)//输入,赋值二维数组s
    16 
    17                 for(j=1;j<=n;j++)
    18 
    19                 {
    20 
    21                      scanf("%d",&a);//为了节省空间,以单个变量输入
    22 
    23                      s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a;
    24 
    25                 }
    26 
    27             scanf("%d",&k);
    28 
    29             while(k--)
    30 
    31             {
    32 
    33                  scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    34 
    35                  sum=s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
    36 
    37                  printf("%lld
    ",sum);
    38 
    39             }
    40 
    41 }
    View Code

    代码分析:

    有三种方法:

    1.    直接求解,按单个元素记录。因此,k次查询里每次都要有两个循环,一个横着在这个区间里扫描,另一个竖着扫描。

    代码如下:

     1 #include<iostream>
     2 
     3 int a[2010][2010],m,n,i,j,k,b,c,d,e;
     4 
     5 long long sum;
     6 
     7 using namespace std;
     8 
     9 int main()
    10 
    11 {
    12 
    13     scanf("%d%d",&m,&n);
    14 
    15     for(i=1;i<=m;i++)
    16 
    17     {
    18 
    19         for(j=1;j<=n;j++)
    20 
    21         scanf("%d",&a[i][j]);
    22 
    23     }
    24 
    25     cin>>k;
    26 
    27     while(k--)
    28 
    29     {
    30 
    31         sum=0;
    32 
    33         scanf("%d%d%d%d",&b,&c,&d,&e);
    34 
    35         for(i=b;i<=d;i++)//两次循环
    36 
    37             for(j=c;j<=e;j++)
    38 
    39                 sum+=a[i][j];
    40 
    41         printf("%lld
    ",sum);
    42 
    43                
    44 
    45     }
    46 
    47 }
    View Code

    这个方法显然效率太低,两次循环太耗费时间了,所以要考虑运用前缀和的办法了。

    2.    利用之前数组储存前缀和的办法,给这个二维数组每行都求一个前缀和,然后在查询时,用要求的区间当中每一行的从y1到y2的和,用s[x][y2]-s[x][y1-1](x为第x行)

    所以采用这个方法效率比上一个方法更快。

    代码:

     1 #include<iostream>
     2 
     3 int a,m,n,i,j,k,b,c,d,e,s[2002][2002]={0};
     4 
     5 long long sum;
     6 
     7 int main()
     8 
     9 {
    10 
    11     scanf("%d%d",&m,&n);
    12 
    13     for(i=1;i<=m;i++)
    14 
    15         for(j=1;j<=n;j++)
    16 
    17         {
    18 
    19             scanf("%d",&a);
    20 
    21             s[i][j]=s[i][j-1]+a;
    22 
    23         }
    24 
    25     scanf("%d",&k);
    26 
    27     while(k--)
    28 
    29     {
    30 
    31         sum=0;
    32 
    33         scanf("%d%d%d%d",&b,&c,&d,&e);
    34 
    35         for(i=b;i<=d;i++)
    36 
    37             sum+=(s[i][e]-s[i][c-1]);
    38 
    39         printf("%lld
    ",sum);
    40 
    41     }
    42 
    43 }
    View Code

    这个方法不用两次循环,可还是有一次循环,但这还不能令人满意,有没有更快的方法呢?

    分析上两个方法,我们发现:

    这是第一个方法,它是以单个元素来求解的(以点做前缀和的)。一步步来累加。

    第二个方法,前缀和,相当于是以行做单位求解。

    既然,以行做前缀和的有了,    以点做前缀和的有了,那能不能以面做前缀和呢?

    分析如下:

    如此,推算赋值公式就如韦恩图那样:

     

    把s[i-1][j]和s[i][j-1]加起来,s[i-1][j-1]部分重叠了,所以要减去,在加上输入的a,就得到:

    s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a;

    而输出就也像上面一样,s[x2][y2]是从坐标(11)开始的,所以要减去s[x2][y1-1]s[x1-1][y2],s[x1-1][y1-1]被多减了,所以要加上。

    代码:

     1 #include<iostream>
     2 
     3 long long sum,a,m,n,i,j,k,x1,y1,x2,y2,s[2002][2002]={0};
     4 
     5 using namespace std;
     6 
     7 int main()
     8 
     9 {
    10 
    11     scanf("%d%d",&m,&n);
    12 
    13     for(i=1;i<=m;i++)
    14 
    15         for(j=1;j<=n;j++)
    16 
    17         {
    18 
    19             scanf("%d",&a);
    20 
    21             s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a;
    22 
    23         }
    24 
    25     scanf("%d",&k);
    26 
    27     while(k--)
    28 
    29     {
    30 
    31         scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    32 
    33         sum=s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
    34 
    35         printf("%lld
    ",sum);
    36 
    37     }
    38 
    39 }
    View Code

    这个方法只用一次运算便求出了解,所以它是三个方法中最快的方法。

  • 相关阅读:
    使用KRPano资源分析工具一键下载全景网站切片图
    使用KRPano资源分析工具解密被加密的XML
    数据库---表---增删改与权限
    数据库---表---表操作练习
    数据库---表---完整性约束
    数据库---表---数据类型
    数据库---表操作---增删改查
    数据库---库操作---表操作
    数据库---初识sql语句
    数据库---mysql的介绍和安装
  • 原文地址:https://www.cnblogs.com/wxjor/p/5524558.html
Copyright © 2020-2023  润新知