题目:来源于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;
}