**关于一维数组的前缀和(求指定区间的所有数的和)文章说明 一维数组前缀和
一、例题
求黄色区域的和
大家可以思考一下这题具体应该怎么做,这里提供给大家几种思路,一种是把这个二维数组分为几行来看,求每一行的指定区间的和,然后把每一行的和加起来,分成几列也是一样的道理;另一种是二重循环,从左上角顶点作为起始点,右下角顶点作为终点把所有数加起来。缺点: 这两种方法总体来说时间复杂度比前缀和方法高,并且操作比较麻烦,如果想连续多次求不同区域的和的话,就要每次都重新输入,不如前缀和简单。
二、前缀和解题思路
做到这题的时候,我们不妨把它离散化,所谓离散化就是把一个大的部分拆成几个小的部分来看,再由小的组合成大的,这题中把他想象求黄色区域面积。黄色区域左上角的坐标为(x1,y1)右下角的坐标为(x2,y2),求这两个坐标围城面积
其中每一块代表一个元素值。
计算面积(所围部分的和)公式:
说明: S[x2][y2]代表(0,0)和(x2,y2)两个点所围成区域的和(或面积),因为两个区域重合部分减了两次。所以还要再加一次重合部分的面积。
三、代码
注意: 在本段代码里面,因为存在i-1和y-1等计算式,所以把数组的第一行和第一列都设置成0不赋值,虽然有点内存的浪费,但是相对于提高了程序的运行速度来说,利大于弊。
#include<cstdio>
#include<iostream>
using namespace std;
const int N = 1010;
int arr[N][N];
int S[N][N]; //前缀数组
//求子矩阵的和
int main() {
int n, m, q; //n行m列,查询q次
printf("请输入行数n和列数m\t");
scanf("%d%d%d", &n, &m, &q);
printf("请输入数组值,建议一行一行的输入,数字和数字之间打空格\n");
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
scanf("%d", &arr[i][j]);
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
S[i][j] = arr[i][j] + S[i - 1][j] + S[i][j - 1] - S[i - 1][j - 1];
}
}
while (q--) {
int x1, x2, y1, y2; //所选区域的两个点
printf("请输入两个点坐标:\n");
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
int sum = S[x2][y2] - S[x1 - 1][y2] - S[x2][y1 - 1] + S[x1 - 1][y1 - 1];
printf("选定区域的和为:%d\n", sum);
}
}