当前位置:首页 > 题解目录 > 正文内容

【题解】最大子矩阵

亿万年的星光2年前 (2023-06-05)题解目录1753

【题目描述】

已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是1 × 1)子矩阵。

比如,如下4 × 4的矩阵

0  -2 -7  0
9  2 -6  2
-4  1 -4  1
-1  8  0 -2

的最大子矩阵是

9 2
-4 1
-1 8

这个子矩阵的大小是15。

【输入描述】

输入是一个N×N的矩阵。输入的第一行给出N(0<N≤100)。再后面的若干行中,依次(首先从左到右给出第一行的N个整数,再从左到右给出第二行的N个整数……)给出矩阵中的N2个整数,整数之间由空白字符分隔(空格或者空行)。已知矩阵中整数的范围都在[−127,127]。

【输出描述】

输出最大子矩阵的大小。

【样例输入】

4
0 -2 -7  0
9  2 -6  2
-4  1 -4  1
-1  8  0 -2

【样例输出】

15

【题目分析】

  • 二维数组其实可以看做一维数组

  • 需要用到  最大字段和 的知识


我们处理二维数组,按照行的数据进行处理,按列求出最大值。

for(i=1;i<=n;i++)
		for(j=1;j<=n;j++){
			scanf("%d",&jz[i][j]);
			jz[i][j]+=jz[i][j-1];
		}

那么,jz数组求出来以后的结果是:

0 -2 -9 -9
9 11 5 7
-4 -3 -7 -6
-1 7 7 5

可以看出,上面的结论是按照行数据,每一个数都是这一行的前面几个数的求和。


【参考代码】

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int jz[105][105]={0};
int main()
{
	int n,i,j;
	scanf("%d",&n);
	//求二维数组的前缀和
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++){
			scanf("%d",&jz[i][j]);
			jz[i][j]+=jz[i][j-1];
		} 
	int sum,max=-1000000000;
	//最大字段和的思想
	for(i=1;i<=n;i++)
		for(j=i;j<=n;j++){
			sum=0;
			for(int k=1;k<=n;k++){
				sum+=jz[k][j]-jz[k][i-1];
				if(sum>max)
					max=sum;
				if(sum<0)
					sum=0;
			}	
		}
	printf("%d\n",max);
	return 0;
}

上面的代码中 ,jz数组求的是二维数组的前缀和。后面求最大字段和除了借鉴前面的思想还可以借助下面的过程:

  1. 初始状态是二维数组(i表示行,j表示列)


    j=1j=2j=3j=4
    i=1
    1,11,21,31,4
    i=22,12,22,32,4
    i=33,13,23,33,4
    i=44,14,24,34,4

当i=1时,我们可以访问(1,1),(1,2),(1,3)(1,4)

当i=2时,我们可以访问(2,2),(2,3),(2,4)

当i=3时,我们可以访问(3,3),(3,4)

当i=4时,我们可以访问(4,4)

也就是下面这样


j=1j=2j=3j=4
i=1
1,11,21,31,4
i=22,12,22,32,4
i=33,13,23,33,4
i=44,14,24,34,4

但是,实际上,上面的代码是三重循环,也就是上图中,所有绿色的点都要执行最内部的一遍for循环。

比如,当(i,j)=(1,1)时,这时最内层循环看jz[k][j]和jz[k][i-1]的变化关系是

k j  -  k  i-1
1 1     1  0   
2 1     2  0  
3 1     3  0
4 1     4  0

这相当于二维数组中第一列每一个数都判断了一遍最大值。

......

当(i,j)=(1,2)时,,这时内层循环看jz[k][i]和 jz[k][i-1]的变化关系是

k j  -  k  i-1
1 2     1  0   
2 2     2  0  
3 2     3  0
4 2     4  0

因为jz数组存的是和的关系。这个地方表示是前两列,每个数相比的最大值。

......

当(i,j)=(2,2)时,,这时内层循环看jz[k][i]和 jz[k][i-1]的变化关系是

k j  -  k  i-1
1 2     1  1   
2 2     2  1  
3 2     3  1
4 2     4  1

这个时候实际上是第二列,因为减法减去了第一列的值

......



扫描二维码推送至手机访问。

版权声明:本文由青少年编程知识记录发布,如需转载请注明出处。

标签: dp动态规划
分享给朋友:

相关文章

【题解】最大公约数(2019青岛市程序设计竞赛)

【问题描述】给定n,以及正整数序列a1,a2,…,an与b1,b2,…,bn。令:sa=a1*a2*…*ansb=b1*b2*…*bn求sa和sb的最大公约数gcd(sa,sb)。【输入】第一行n。第...

【题解】单词排序

【题目描述】输入一行单词序列,相邻单词之间由一个或者多个空格间隔,请按照字典序输出这些单词,要求重复的单词只输出一次。(区分大小写)【输入描述】一行单词序列,最少一个单词,最多100个单词,每个单词长...

【题解】银行排队

【题目描述】我们大多都有在银行排队的经历,唉,那坑爹的排队啊!现在就让我们来算算我们这些客户平均需要等多久吧。每天刚开始时银行会开m个窗口来为我们total个客户办理业务,当有客户需要办理业务时,先选...

哥德巴赫猜想

【题目描述】哥德巴赫猜想的命题之一是:大于6 的偶数等于两个素数之和。编程将6~100所有偶数表示成两个素数之和。【输入描述】无【输出描述】分行输出例如:6=3+38=3+5…(每个数只拆开一次,请保...

【NOIP2000】计算器的改良

【题目描述】NCL 是一家专门从事计算器改良与升级的实验室,最近该实验室收到了某公司所委托的一个任务:需要在该公司某型号的计算器上加上解一元一次方程的功能。实验室将这个任务交给了一个刚进入的新手 ZL...

【题解】区间和

1.区间和(sum.cpp)【描述】输入一个整数Q,进行Q次询问,每次给定两个整数l和r,每一次输出l~r中所有平方数的和 % 1000000007【输入】第一行是一个整数Q后面的Q行每行有...