二维前缀和暴力算法

例题

 暴力解法代码

#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]值均为初始化的零,求和公式依旧适用。
 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值