基于贪心算法、动态规划对求解最大子矩阵问题的深入研究

本文介绍了一种使用动态规划求解二维矩阵中最大子矩阵和的高效算法,首先讲解了一维数组最大子序列和的求解方法,然后扩展到二维矩阵,通过控制列的起点和终点,将矩阵转化为一维数组求解。

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

背景及必备知识

总所周知,矩阵实质就是一个二维数组。所以想要求最大子矩阵,不如先来看看如何求一位数组的最大子序列和吧!

  • 现假设有一个一维数组 arr[n],要你找出连续的一段数组元素,使其和最大
  • 例如,一个一维数组:4 -5 6 3 7 -1 8 ,通过肉眼观察, 6 3 7 -1 8 为这个数组的连续最大和。那么有什么算法能够解决这个问题呢?
    我们可能看一眼就能想到的方法就是用三层循环来枚举吧!
    是不是像这样~~
int max_sum, tmp_sum;
for(int i = 0, i < n; i++) {
	for(int j = 0; j <= i; j++) {
		tmp_sum = 0;
		for(int k = j; k <= i; k++) {
			tmp_sum += arr[k];
		}
		if (tmp_sum > max_sum)
			max_sum = tmp_sum;
	}
}

这样确实可以,但显然时间复杂度太高了,不好。

于是我向大家隆重推出今天的主角:用动态规划,以O(n)的复杂度来做。(我还是结合代码来讲吧)

int get_maxsum(int arr[],int m)
{
	int t=0;
	int Max=0;
	for(int i=1;i<=m;i++)
	{
		if(t>=0) t+=arr[i];//如果前面累加的大于0,说明它能增大当前数
		                   //那当前最优策略就是让当前的数加入原先的序列
		else t=arr[i];//如果前面累加的数小于等于0,则它对当前数无帮助
		              //则还不如以当前的数另起一个序列
		Max=max(Max,t);//记录
	}
	return Max;
}

问题分析

好了,现在我们知道了如何求一维数组中的最大子序列。
那如何把一维拓展到二维呢?(先自己想想吧!)

其实很简单~~
先来看张图片
在这里插入图片描述

  • 假设我们要求的最大子矩阵是原矩阵的第 i 行到第 j 行,第 k 列到第 s 列,那么如下图所示,圈出的范围即最大子矩阵。我们将最大子矩阵的每一列各自加和,就可以得到一个一维数组
  • 该一维数组的各个元素为a[i][k] +······+ a[j][k], ···+···+··· , a[i][s] +······+ a[j][s]。

从上面的idea中我们可以得出解决此问题的基本思想:

  • 控制新的子矩阵开始,每列中的元素累加变成一维数组中的各个元素,然后再求一维数组最大子序列的和。

懂了吗?
还有点昏的话,看看代码吧!

Code

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

int n,m;
int Map[120][120],max_sum=0;

int work(int arr[],int m)//前面讲过了,就是dp的方法
{
	int t=0;
	int Max=0;
	for(int i=1;i<=m;i++)
	{
		if(t>=0) t+=arr[i];
		else t=arr[i];
		Max=max(Max,t);
	}
	return Max;
}

int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			scanf("%d",Map[i]+j);//用Map数组存储该矩阵
		}
	}
	int col[120];
	for(int i=1;i<=n;i++)//控制所累加列的起点
	//这层i循环及下面的j循环放在一起起了枚举了所有行层的作用(这里有点儿难理解,好好想想)
	{
		memset(col,0,sizeof(col));//以新的起点开始累加
		for(int j=i;j<=n;j++)//控制所累加列的终点
		{
			for(int k=1;k<=m;k++)//对各个列进行累加操作
			{
				col[k]+=Map[j][k];
			}
			max_sum=max(max_sum,work(col,m));//求解这些列所构成的一位数组的最大子序列
		}
	}
	cout<<max_sum;
	return 0;
}

这就好了呀!对,就这么巧妙!
好好回味一下吧,相信你最后一定能获得一种别有洞天的感觉!

学习厌倦了?点我有更多精彩哦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值