poj 1050-小白算法练习 to the max 动态规划

本文介绍了一种解决二维矩阵中寻找最大子矩阵和的方法,通过动态规划将问题转化为一维数组的最大子数组和问题。

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

To the Max
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 49226 Accepted: 26074

Description

Given a two-dimensional array of positive and negative integers, a sub-rectangle is any contiguous sub-array of size 1*1 or greater located within the whole array. The sum of a rectangle is the sum of all the elements in that rectangle. In this problem the sub-rectangle with the largest sum is referred to as the maximal sub-rectangle. 
As an example, the maximal sub-rectangle of the array: 

0 -2 -7 0 
9 2 -6 2 
-4 1 -4 1 
-1 8 0 -2 
is in the lower left corner: 

9 2 
-4 1 
-1 8 
and has a sum of 15. 

Input

The input consists of an N * N array of integers. The input begins with a single positive integer N on a line by itself, indicating the size of the square two-dimensional array. This is followed by N^2 integers separated by whitespace (spaces and newlines). These are the N^2 integers of the array, presented in row-major order. That is, all numbers in the first row, left to right, then all numbers in the second row, left to right, etc. N may be as large as 100. The numbers in the array will be in the range [-127,127].

Output

Output the sum of the maximal sub-rectangle.

Sample Input

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

8  0 -2

Sample Output

15

翻译

给出一个有正整数和负整数的二维的向量,附属矩阵是在向量中数个矩形就是其附属矩形,(>1*1),附属矩形的和是各个元素的和

IN

第一行:N代表这个N*N矩阵的维数

接下来几行输入16个整数,以空白符相隔无论是space还是tab还是enter

OUT

第一行(最有一行):附属矩形和的最大数 

第一行:N代表这个N*N矩阵的维数

分析:

在做这道题之前必须会最大字段和这一道题的基础,这也是动态规划中最简单的一道例题,而这道题是最大字段和的一个扩展。

例子: 0,2,7,2,-5最大的一个连续子序列之和。

分析:这五个数有这样几种和的组合:0;02;027;0272;……这样5!个数。

   用数组索引来表示就是:0;0到1;0到2;0到3……1;1到2;……(这里是数组索引表示)

   我们显然不能用多重循环把所有数都算出来,我们换一种角度思考,如果只有一个数字,那么最大的连续子序列数多少,还是以上面的例子为例,应该是0吧,那么现在有两个数字呢有两种情况,一种是前面有一个数字的最大值(已求)+现在这个数字;另外一种情况是就是只有这个数字然后算出来的最大值与只有一个数字的情况的最大值相比较;现在有三个数字也有两种情况,一种是前面有前面两个数字的最大值+现在这个数字;或者就是只是这个数字;……

代码:

第一行:N代表这个N*N矩阵的维数

  1. int max_sum(int n)
    {
             int i, sum = 0, max = INT_MIN;  
             for(i = 0; i < n; i++)
             {  -------------------------------------------------------------------------------0
                    if(sum < 0)
                            sum = 0;
                    sum += a[i];      ---------------------------------------------------------1
                    if(sum > max)
                            max = sum;---------------------------------------------------------2
             }
             return max;
    }

哭上面把文字变成代码就是我们普通程序员做的事情,文字表述部分就是大神们做的事情。哭

算了,不哭了,我来解释一下为什么文字翻译成了一样一些代码。

----0----代表蓝色部分【这个不用说循环】

----1----代表橙色部分【**下面说**】

----2----代表紫色部分

我们橙色的字;因为一共有两种情况,一种是自己本身,一种是前i-1项的最大值,我们换个思路想一下,假如第1个数(索引为0的数)为负数,那么下面前两个数的最大最一定是第二个数其本身,即第二次是把sum=0;sum+=a[1]  然后记录max值。。。实际上就是假如你前n个数是正的那么可以继续加上去,如果你前n个数是负的那么把值记录一下就好了。所以只要求前n项和和最大值就好了。

当然也有人是这样写的:

  1. int MaxSum(int n,int *a)  
  2. {  
  3.     int sum=0,b=0;  
  4.     for(int i=1; i<=n; i++)  
  5.     {  
  6.         if(b>0)  
  7.         {  
  8.             b+=a[i];  
  9.         }  
  10.         else  
  11.         {  
  12.             b=a[i];  
  13.         }  
  14.         if(b>sum)  
  15.         {  
  16.             sum = b;  
  17.         }  
  18.     }  
  19.     return sum;  

或者更加直白的话是这样写的,这样更加容易理解一些,看个人的编程习惯了

  1. int max_sum2(int n)
    {
         b[0]=a[0];    //数组b存放前n项的最大值
         int maximal=b[0];
         for(int i=1;i<n;i++)
         {
               b[i]=max(b[i-1]+a[i],a[i]); //STL
               if(b[i]>maximal)
                    maximal=b[i];
         }
         return maximal;
    }

下面写二维的矩阵这道题,我们首先要做的就是降维然后像上面一样做。

代码:

先写一下思路,为什么说是最大字段和的扩展。。。

我们原来是一行,如果算到两行的话。。。现在我们下面一行跟着上面一行一起动,再求和。即如果这个矩阵只有两行,我们先求第一行的最大值(最大字段和),然后让第二行跟着第一行一起动【其实就是把两行看成一行】,求出两行的最大值。。。以此类推。

我们知道一维时候的最大字段和,要有sum【前n个数之和】和最大值这两个变量,我们这里的sum怎么求呢? sum[i][j]从表示第i行第j个元素变成表示第i行前j个元素和,这样sum[k][j]-sum[k][i]就可以表示第k行从i->j列的元素和
代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int MAX=101;
int arr[MAX][MAX]={0};
int Dy[MAX][MAX]={0};
int main(){
	int N;
	cin>>N;
	for(int i=1;i<=N;i++)
	{
		for(int j=1;j<=N;j++)
		{
			cin>>arr[i][j];
		 	Dy[i][j]=Dy[i][j-1]+arr[i][j]; //让Dy存放第i行的前j项和
			//其实我们用数学之美来看为什么要这样存放,你一维的时候存放的是一维的数据
			//二维的时候再存放一维的数据就是错误的,二维的时候就应该存放二维的数据
			//当然你也不要去存放前i行前j列之和,这个相比于前面的就是三维的数据了
			//如果你算的是长方体的数据,这样应该是对的,那么我们的数组也应该是三维的了 
		}
	}
	int max=INT_MIN;
	int sum; 
	for(int i=1;i<=N;i++)
	{
		for(int j=i;j<=N;j++)
		{   
	     	sum=0;
		//前面两层循环是列循环,比如三列的话就是,1-2列,1-3列,2-3列 
			 for(int k=0;k<=N;k++)
			 {
			 //行循环,求和
			     if(sum<0) sum=0;
				 sum+=(Dy[k][j]-Dy[k][i-1]);
			     if(sum>max) max=sum;			 	
			 } 
			 
		}
	}
	cout<<max<<endl;
} 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值