例题
暴力解法代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
const int Max = 500;
//数组的初始化问题
//全局数组,未初始化时,默认值都是 0;
//
//局部数组,未初始化时,默认值为随机的不确定的值;
//
//局部数组,初始化一部分时,未初始化的部分默认值为 0;
int map[Max][Max];
int sums[Max][Max] ;
int N = 0, M = 0, K = 0;
void findRightBottom(int leftAbovex, int leftAbovey,int& count) {
for (int rightBottomx = leftAbovex; rightBottomx <= N; ++rightBottomx) {
for (int rightBottomy = leftAbovey; rightBottomy <= M; ++rightBottomy) {
//套公式
long long result = sums[rightBottomx][rightBottomy] - sums[rightBottomx][leftAbovey-1]
- sums[leftAbovex - 1][rightBottomy] + sums[leftAbovex-1][leftAbovey-1];
if (result <= K)
count++;
}
}
}
int main() {
cin >> N >> M >> K;
for (int i = 1; i <= N; ++i) {
for (int j = 1; j <= M;++j) {
cin >> map[i][j];
}
}
//公式:sums[i][j] = sums[i-1][j] + sums[i][j-1] +map[i][j];
for (int x = 1; x <= N; ++x) {
for (int y = 1; y <= M; ++y) {
sums[x][y] = sums[x - 1][y] + sums[x][y - 1] - sums[x-1][y-1] + map[x][y];
}
}
int count = 0;
//找左上角
for (int leftAbovex = 1; leftAbovex <= N; ++leftAbovex) {
for (int leftAbovey = 1; leftAbovey <= M; ++leftAbovey) {
//找右下角
findRightBottom(leftAbovex,leftAbovey,count);
}
}
cout << count;
return 0;
}
解题思路
1.套公式制作前缀和图--sums[][]
2.从前缀和图的左上角开始遍历,固定子矩阵的左上角。然后从左上角开始接着遍历,固定子矩阵的右下角。套公式求元素和
3.判定。
前缀和算法公式
1.求该处坐标的前缀和(制作前缀和图):
sums[x][y] = sums[x - 1][y] + sums[x][y - 1] - sums[x-1][y-1] + map[x][y];
2.求任意子矩阵所有元素之和
算法要点:定位好矩阵的左上角元素坐标,再定位好矩阵的右下角坐标,套公式即可。
long long result = sums[rightBottomx][rightBottomy] - sums[rightBottomx][leftAbovey-1]
- sums[leftAbovex - 1][rightBottomy] + sums[leftAbovex-1][leftAbovey-1];
以空间换取思维量的减少技巧
在进行二维图的设计时,可以从数组索引为1开始赋值。索引为0空位不赋值
如此好处:
让元素的序号(即:当前元素是第几个元素)与数组(容器)的索引相一致,从而避免元素序号与索引相差1所可能带来的问题。
本题中额外好处:
对于求前缀和时的临界情况----坐标出现x==0或y==0的所有sums数组元素,无需再单独拎出来进行代码处理,因为sums[0][y]以及sums[x][0]值均为初始化的零,求和公式依旧适用。