poj 1050 To the Max 求矩阵中局部矩形区域和最大值

题目:来源于http://poj.org/problem?id=1050

描述:给定一个矩阵,求出其包含的矩形区域的最大值(矩形区域总所包含的所有元素都要算)。具体如下:

            0 -2 -7 0
            9 2 -6 2       最大值区域:       
9   2
           -4 1 -4 1                           -4   1
           -1 8 0 -2                           -1   8

 

测试用例:


4   (第一行表示是n*n的矩阵,即紧接着输入n*n个矩阵元素)
0 -2 -7 0 
9 2 -6 2
-4 1 -4 1 
-1 8 0 -2
 
输出结果:15

思路:

       

        本题虽然为矩阵,但思想就是将它转化为一列数,然后再求最大子序列和。但如何转化?

                 7 -8 9

                -4 5 6

                1 2 -3

        主要是将同一列中的若干数合并。比如,从第一行开始,到第2行结束,每一列的和组成的序列为:

               3 -3 15

        然后求此序列的最大子序列和。求出后与max比较,最后输出的一定是最大矩阵和。

除了按照程序中按初始位置和结束位置枚举外,还可以枚举每一列中的元素个数和起始位置写循环。

即如下的过程

      (1)第一轮:第一次以第1行合并、第二次1、2行合并、三次1、2、3。。。分别求出合并后的局部最大值,则包含第1行的矩形最大值则可以在第一轮求出;

      (2)第二轮:第一次以第2行合并、第二次2、3行合并、三次2、3、4。。。分别求出合并后的局部最大值,则包含第2行的矩形最大值则可以在第一轮求出;

      (3)第三轮:第一次以第3行合并、第二次3、4行合并、三次3、4、5。。。分别求出合并后的局部最大值,则包含第3行的矩形最大值则可以在第一轮求出;

        。。。如此进行n次,则就可求出矩阵中包含矩形中的最大值。代码如下:

#include <iostream>
#include<cstdlib>

using namespace std;
#define MIN -32768
class TotheMax{
public:
	TotheMax(int n){
		this->n = n;
	}
	void solution()
	{
		int i,j,k;
		int ans = MIN;
        int **matrix = new int*[n];//分配矩阵空间
		int *temp = new int[n];//保存合并后的数组元素,以便求局部最大值
		for(i=0;i<n;i++){
			matrix[i] = new int[n];
		}

		for(i=0;i<n;i++)//输入矩阵元素
			for(j=0;j<n;j++)
				cin>>matrix[i][j];

		for(i=0;i<n;i++){//第i轮合并

			for(k=0;k<n;k++){//memset为什么不行???
				temp[k] = 0;
			}
			for(j=i;j<n;j++){
				for(k=0;k<n;k++){
					temp[k] += matrix[j][k];//合并
				}
				int d = findMaxSubstr(temp,0,n);
				if(d>ans)ans = d;
			}
		}
		cout<<ans;

		delete[] temp;
		for(i=0;i<n;i++)delete[] matrix[i];
		delete[] matrix;
	}
protected:
//     int findMaxSubstr(int arr[],int len)//求数组中局部最大值,比较常见的解法
// 	{
// 		int i;
// 		int sum = 0;
// 		int max = MIN;
// 		for(i=0;i<len;i++){
// 			sum += arr[i];
// 			if(sum>max)max = sum;
// 			if(sum<0)sum = 0;
// 		}
// 		return max;
// 	}
	int findMaxSubstr(int arr[],int start,int end)//编程之美上的分治解法
	{
		if(start==end)return arr[start];
		int left,right;
		int result;
		int mid = start+((end-start)>>1);
		left = findMaxSubstr(arr,start,mid);
		right = findMaxSubstr(arr,mid+1,end);
		int i = mid - 1;
		int j = mid + 1;
		int sum = arr[mid];
		int maxsum = arr[mid];
		while(i>=start){
			sum += arr[i];
			if(sum>maxsum)maxsum = sum;
			i--;
		}
		sum = maxsum;
		while(j<end){
			sum += arr[j];
			if(sum>maxsum)maxsum = sum;
			j++;
		}
		
		if(maxsum>left)return maxsum>right?maxsum:right;
		else return left>right?left:right;
	}
private:
	int n;
};


int main()
{
	int n;
	cin>>n;
	TotheMax poj1050(n);
	poj1050.solution();
	system("pause");
	return 0;
}


 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值