编程之美——字数组之和的最大值(二维,动态规划)

把前一个问题扩展了一下,寻找二维数组中,从(x1, y1)到(x2, y2)确定的矩形区域的数据之和最大值。

解法一给出了一个技巧,建立一个和原数组一样大的数组,用来保存(0, 0)到(x, y)的和,即P[x][y] = sum(x[0][0] –> x[x][y])。然后用Sum = PS[i_max][j_max]  - PS[i_min - 1][j_max] – PS[i_max][j_min - 1] + PS[i_min - 1][i_min -1]。不知道书上为什么要让数组从1开始,然后把数组的边界置0。

解法二用了分治的思想,或者动态规划吧。先假定一个边界,用穷举遍历这些边界,再把选定的数据变换为一维数据,根据上一节的算法进行分析。

扩展问题:

1. 收尾相连后,就只能上下确定边界,然后按照一维的解法进行求解。

2. 上下也相连,就要两个方向都按照首尾相邻的情况考虑了。

3、4. 三维和四维的情况,至少可以先在两个方向上遍历,在另一方向上上先求和再按一维情况求解吧。

1. 简述

给定一个n*n(0<n<=100)的矩阵,请找到此矩阵的一个子矩阵,并且此子矩阵的各个元素的和最大,输出这个最大的值。
    Example:
     0 -2 -7  0 
     9  2 -6  2 
    -4  1 -4  1 
    -1  8  0 -2 
    最大子矩阵为:
    9 2 
   -4 1 
   -1 8

2. 原理

最大子矩阵和是最大子序列和的二维扩展。
    穷举所有子矩阵的话,有C(n,2)*C(n*2)/2个子矩阵,就是n^4个子矩阵,这还不算每个子矩阵求和的时间,就到了O(n^4)。
    转化为最大子序列求解的思路是:固定第i列到第j列的范围,寻找在这个范围内的最大子矩阵,这个寻找过程,把每行第i列上的元素到第j列的元素分别求和,就转变为了一维的情况。由于有C(n,2)种列的组合,而求一维的子序列需要n的时间,所以,总体上时间复杂度为O(n^3)。

3. 递推公式

A的下标从0开始,为了增加哨兵,F,P,Q的下标都从1开始。    
    · A[N][N]表示输入矩阵。
    · F[N+1][N+1],F[i][j]表示从第i行的第0列到第j列的元素和。
    F[i][j]=0,j=0
      F[i][j]=A[i-1][j-1], j=1
      F[i][j]=F[i][j-1]+A[i-1][j-1],j>1
      这样当固定第i列到第j列的时候,转化为一维数组的第k个元素就可以表示为F[K][j]-F[K][i-1],K是行下标,i和j都是列下标,由于矩阵的统计是从1开始的,所以i,j,k都是大于等于1的,即i-1不会下标越界,这就是前面哨兵的作用。
    固定i列和j列的时候的求解递推公式:
    · P[N+1],P[k]表示固定第i列到第j列时,从第1行到第k行范围内,包括第k行的最大子矩阵。
    · Q[N+1],Q[k]表示固定第i列到第j列时,从第1行到第k行范围内,最大子矩阵。
      P[k]=F[0][j]-F[0][i-1], k=1
      P[k]=P[k-1]>0?(P[k-1]+F[k][j]-F[k][i-1]):(F[k][j]-F[k][i-1]),k>1
      Q[k]=P[k], k=1
      Q[k]=max{Q[k-1], P[k]}, k>1
      Q[N]即为固定列(i-j)范围内的最大和。

#include<iostream>
#include<vector>
#include<math.h>
using namespace std;

//

int Maxval_temp(int* a,int n)
{
	if(n==1)
		return a[n-1];
	int maxall=a[n-1];
	int maxstart=a[n-1];
	for(int i=n-2;i>=0;i--)
	{
		maxstart=max(a[i],a[i]+maxstart);
		maxall=max(maxall,maxstart);
	}
	return maxall;
}

int MaxVal(vector<vector<int>> vec)
{
	if(vec.empty())
		return 0;
	int m,n;
	m=vec.size();
	n=vec[0].size();
	if(m==1)
		return vec[0][0];
	int max_val=vec[0][0];
	for(int i=0;i<m;i++)
		for(int j=i;j<m;j++)
		{
			int* ptr=new int[n];
			for(int k=0;k<n;k++)
			{
				int temp1=0;
				for(int g=i;g<j;g++)
					temp1+=vec[k][g];
				ptr[k]=temp1;
			}
			int temp_max=Maxval_temp(ptr,n);
			if(temp_max>max_val)
				max_val=temp_max;
		}
	return max_val;
}

int main()
{

}

  

时间: 2024-08-09 00:09:42

编程之美——字数组之和的最大值(二维,动态规划)的相关文章

数字之魅:子数组之和的最大值[二维]+[三维]

题目:如何求出一个二维数组中的最大子数组之和. 方案一:暴力破解-枚举法.对于一个二维数组我们列举出每一个子数组值的大小,然后进行比较,这样就可以得到最大的和了.其时间复杂度为:O(N*N*M*M*Sum的时间复杂度)[N表示行数,M表示列数,Sum是求解子矩阵的和].由于Sum函数求和也是采用循环,足见这个时间复杂度可是相当的大. 方案二:先计算出以左上角的元素(1,1)和当前元素(i,j)为顶点对的子矩阵的部分和,部分和的计算如下图(一)所示,我们可以看出:以(i_min,j_min),(i

编程之美----寻找数组中的最大值和最小值

对于一个由N个整数组成的数组,需要比较多少次才能把最大和最小的数找出来呢? 解法:最简单的是扫描一遍数组,需要比较2*N次才能求解. 解法二:首先在概念上把连个相邻的数分在同一组,只是想象而已,无须任何操作.然后比较同一组的奇数位数字和偶数位数字,将较大的数放在偶数位上,较小的数放在奇数位上.N/2次比较久可以调好.然后求出偶数位上的Max,和奇数位上的Min,各须比较N/2次.总共须比较1.5*N次.  若不破坏原数组,只需用两个变量Max和Min来存储当前的最大值和最小值,当比较完奇数位和偶

编程之美之队列中取最大值操作

问题: 假设有这样一个拥有3个操作的队列: 1. EnQueue(v): 将v加入队列中 2. DeQueue(): 使队列中的队首元素删除并返回此元素 3. MaxElement: 返回队列中的最大元素 设计一种数据结构和算法,让MaxElement操作的时间复杂度尽可能地低. #include<iostream> #include<limits.h> using namespace std; class Stack { public: Stack() { stackTop =

求数组中最大子数组的和(二维环)

成员:林彦汝.张金 (这次角色调换,我主要负责代码复审,代码测试计划:张金负责程序分析,代码编程.) 题目: 返回一个二维整数数组中最大子数组的和 要求: 输入一个二维整形数组,数组里有正数也有负数. 二维数组首尾相接,象个一条首尾相接带子一样. 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. 求所有子数组的和的最大值. 思路: 在求一维环形数组和二维数组最大子数组的和的基础上,我们将两个的方法综合起来求解关于二维环形数组.假设原二维数组a[3][3]为 1 -2 3 1 -3

c#(6)——数组的应用和二维数组

人类思维--计算机逻辑思维逻辑思维--代码实现 写书法:描红——临摹——碑贴——自成一体——草 复习:数组:一维,二维,多维一维:豆角.连续,同一类型.定义:数据类型[] 数组名=new 数据类型[长度]{.,.,.,.};赋值:数组名[下标] = 值取值:数组名[下标]灵活运用:与for循环的结合应用.1.求最大值,最小值.2.求总和,平均.3.随机(生成下标)抽值. 数组的应用:(一).冒泡排序.1.冒泡排序是用双层循环解决.外层循环的是趟数,里层循环的是次数.2.趟数=n-1:次数=n-趟

Android 在资源文件(res/strings.xml)定义一维数组,间接定义二维数组

经常我们会在资源文件(res/strings.xml)定义字符串,一维数组,那定义二维数组?直接定义二维数组没找到,可以间接定义. 其实很简单,看过用过一次就可以记住了,一维数组估计大家经常用到,但是二维数组应该比较少用,因为只能间接定义二维数组. 数组的定义: 数组就是一次性定义相同数据类型的一组变量数组定义. 数组的特点: 1.数组是相同数据类型的元素的集合. 2.数组中的各元素是有先后顺序的,它们在内存中按照这个先后顺序连续存放在一起. 3.数组元素用整个数组的名字和它自己在数组中的顺序位

数组合并函数,二维数组相同字段合并到一起。

一般从数据库中提取数据时,会遇到各种各样类型的数据,要求也不尽相同.自己这两天开发的时候遇到一个很纠结的问题,如下: 比如一个二维数组是这样的: Array ( [0] => Array ( [uid] => 231 [username] => 123456 [active] =>aaaa [transfer] =>1111 ) [1] => Array ( [uid] => 231 [username] =>123456 [active] => bb

例看二维数组,指针,二维数组指针

例程: /****************************************************** * * 文件名:例程 * * 文件描述:例看二维数组,指针,二维数组指针 * * 创建人:Jesse * * 版本号: * * 修改记录: * ******************************************************/ #include <stdio.h> #define ROW 3 #define LINE 3 void main(voi

C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com

原文:C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 本文由 arthinking 发表于315 天前 ⁄ itzhai.com原创文章 ⁄ C语言 ⁄ 评论数 3 ⁄ 被围观 1,775 views+ 指针数组: 在一个数组中,如果它的元素全部都是指针类