最大面积子矩阵(二维前缀和)

该博客讨论如何利用二维前缀和解决寻找矩形空地上平均海拔高于海平面的最大宫殿建设区域问题。输入为矩形空地的海拔高度,输出为最大面积。示例输入和输出分别给出了一个3*2的地形和结果4。二维前缀和公式用于计算每个位置的和,数据限制为N,M≤100。" 134958748,10163228,Oracle数据库在线重定义分区表实战指南,"['数据库', 'Oracle', '分区表', '数据迁移']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

一块N*M的矩形空地。空地中每个格子都有自己的海拔高度。选择一个矩形区域建设宫殿,宫殿的平均海拔在海平面之上,而且希望宫殿尽量大,请问宫殿最后会有多大?

Input Format

第一行为N和M。之后N行,每行M个数,描述的空地的海拔。

Output Format

输出一行,表示宫殿最大面积。

Sample Input

3 2
4 0
-10 8
-2 -2

Sample Output

4

Data Limit :N,M≤100;

二维前缀和公式:s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + x;

CODE

#include <bits/stdc++.h>
using namespace std;

long long s[109][109];
int n,m;
long long ans;

int main()
{
	cin>>n>>m;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			{
				int x;
				cin>>x,
				s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + x;    //计算前缀和(第一步)
			}
	long long i1,i2,j1,j2;		//我也不知道为什么全要玄学开long long
	for (i1 = 1; i1 <= n; i1++)         //枚举各种面积(玄学,我也不懂)
		for (j1 = 1; j1 <= m; j1++)
			for (i2 = i1; i2 <= n; i2++)
				for (j2 = j1; j2 <= m; j2++)
					{
						lon
### 二维前缀和算法概述 二维前缀和是一种高效的预处理技术,用于快速计算任意子矩阵的元素之和。通过构建一个前缀和矩阵 `prefixSum`,可以将原本时间复杂度为 \(O(n \times m)\) 的操作优化到常数级别的时间复杂度。 #### 前缀和矩阵定义 假设有一个大小为 \(n \times m\) 的原始矩阵 `matrix`,其对应的前缀和矩阵 `prefixSum[i][j]` 定义如下: \[ prefixSum[i][j] = \sum_{p=0}^{i}\sum_{q=0}^{j} matrix[p][q] \] 即,`prefixSum[i][j]` 表示从原点 `(0, 0)` 到位置 `(i, j)` 所有元素的累加和[^1]。 --- ### 构建前缀和矩阵的方法 为了高效地计算前缀和矩阵,可以通过动态规划的方式完成。具体公式如下: \[ prefixSum[i][j] = \begin{cases} matrix[0][0], & i = 0, j = 0 \\ prefixSum[i-1][j] + matrix[i][j], & i > 0, j = 0 \\ prefixSum[i][j-1] + matrix[i][j], & i = 0, j > 0 \\ prefixSum[i-1][j] + prefixSum[i][j-1] - prefixSum[i-1][j-1] + matrix[i][j], & i > 0, j > 0 \end{cases} \] 此公式的含义是利用重叠区域避免重复计算,从而提高效率。 以下是基于 Java 实现的代码示例: ```java public class PrefixSumMatrix { public static int[][] buildPrefixSum(int[][] matrix) { if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { return new int[0][0]; } int n = matrix.length; int m = matrix[0].length; int[][] prefixSum = new int[n][m]; for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { prefixSum[i][j] += matrix[i][j]; // 当前单元格值 if (i > 0) { // 上方贡献 prefixSum[i][j] += prefixSum[i-1][j]; } if (j > 0) { // 左边贡献 prefixSum[i][j] += prefixSum[i][j-1]; } if (i > 0 && j > 0) { // 左上角被多减一次,需加上 prefixSum[i][j] -= prefixSum[i-1][j-1]; } } } return prefixSum; } public static void main(String[] args) { int[][] matrix = {{3, 0, 1, 4, 2}, {5, 6, 3, 2, 1}, {1, 2, 0, 1, 5}, {4, 1, 0, 1, 7}, {1, 0, 3, 0, 5}}; int[][] prefixSum = buildPrefixSum(matrix); System.out.println("Prefix Sum Matrix:"); for (int[] row : prefixSum) { for (int val : row) { System.out.print(val + " "); } System.out.println(); } } } ``` --- ### 使用前缀和矩阵查询子矩阵和 给定左上角坐标 `(r1, c1)` 和右下角坐标 `(r2, c2)`,目标是从矩阵中提取该范围内的所有元素并求和。借助前缀和矩阵,可以直接通过以下公式得到结果: \[ subMatrixSum(r1, c1, r2, c2) = prefixSum[r2][c2] - prefixSum[r1-1][c2] - prefixSum[r2][c1-1] + prefixSum[r1-1][c1-1] \] 注意边界条件:如果某一项超出矩阵范围,则将其视为零。 下面是完整的函数实现: ```java public static int getSubMatrixSum(int[][] prefixSum, int r1, int c1, int r2, int c2) { int total = prefixSum[r2][c2]; int above = (r1 > 0) ? prefixSum[r1-1][c2] : 0; int left = (c1 > 0) ? prefixSum[r2][c1-1] : 0; int topLeft = ((r1 > 0) && (c1 > 0)) ? prefixSum[r1-1][c1-1] : 0; return total - above - left + topLeft; } // 测试调用 System.out.println(getSubMatrixSum(prefixSum, 2, 1, 4, 3)); // 查询指定子矩阵的和 ``` --- ### 性能分析 - **空间复杂度**: 需要额外存储整个前缀和矩阵,因此空间复杂度为 \(O(n \times m)\)[^1]。 - **时间复杂度**: - 构造前缀和矩阵的过程需要遍历整个输入矩阵,时间为 \(O(n \times m)\)。 - 单次查询子矩阵和的操作仅涉及固定数量的数组访问,故时间复杂度为 \(O(1)\)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值