标签:
题目:如何求出一个二维数组中的最大子数组之和。
图一 图二
方案三:其实我们仔细的想一想,就可以发现,它的最简单的原型是求一维数组中的最大值。那么基于这个启发,我们可以把问题从二维转化为一维以提高算法性能。假设已经确定了矩阵区域的上下边界,知道矩阵区域的上下边界分布是第a行和第c行,就把每列的第a行和第c行之间的元素看成一个整体。即求数组:(merge[1],merge[2],merge[3]....).merge[i]=arr[a][i]+arr[b][i]+..+arr[c][i].
这样我们可以枚举矩形的上下边界,然后再用一维情况下的方法确定左右边界,相当于一维数组中的一个元素(通过子矩阵部分和可以在O(1)时间内计算出整体之和),就可以得到二维问题的解。新方法的时间复杂度为:O(N*N*M)=O(N*N*N)。具体过程如下图三所示:
图三
方案一的具体实现代码:int arr[N][M]; int Max(int x,int y)//得到最大值; { return (x>y)?x:y; } int Sum(int imin,int imax,int jmin,int jmax)//得到子矩阵的和,时间复杂度为O(N*N); { int sum=0; for(int i=imin;i<=imax;i++) for(int j=jmin;j<jmax;j++) sum+=arr[i][j]; return sum; } int MaxSum(int *arr,int m,int n) //得到子矩阵的最大值; { int maximum=0; for(int i_min=1;i_min<=n;i_min++) for(int i_max=i_min;i_max<=n;i_max++) for(int j_min=1;j_min<=m;j_max++) for(int j_max=j_min;j_max<=m;j_max++) maximum=Max(maximum,Sum(i_min,i_max,j_min,j_max)); return maximum; }方案二的具体实现代码:
int arr[N][M]; int Sum[N][M];//存储部分和的数组; int Max(int x,int y)//得到最大值; { return (x>y) ? x:y; } void GetSum()//预处理得到部分和; { for(int i=0;i<=n;i++) Sum[i][0]=0;//边界值; for(int j=0;j<=n;j++) Sum[0][j]=0;//边界值;真正的部分和数据是从Sum[1][1]开始的; for(i=1;i<=n;i++) for(j=1;j<=m;j++) Sum[i][j]=Sum[i-1][j]+Sum[i][j-1]-Sum[i-1][j-1]+arr[i][j] } inline int Sum(int i_min,int i_max,int j_min,int j_max)//调用比较频繁,可设置为内联函数,提高效率。和方案一相比,其时间复杂度为O(1). { return Sum[i_max][j_max]-Sum[i_min-1][j_max]-Sum[i_max][j_min-1]+Sum[i_min-1][j_min-1]; } int MaxSum(int *arr,int m,int n) { int maximum=0; for(int i_min=1;i_min<=n;i_min++) for(int i_max=i_min;i_max<=n;i_max++) for(int j_min=1;j_min<=m;j_max++) for(int j_max=j_min;j_max<=m;j_max++) maximum=Max(maximum,Sum(i_min,i_max,j_min,j_max)); return maximum; }方案三的具体实现代码:
#include <iostream> #include <algorithm> using namespace std; #define LEN 888 int arr[LEN][LEN]; long long Sum[LEN][LEN]; inline long long MatrixSum(int s, int t, int i, int j) { return Sum[i][j]-Sum[i][t-1]-Sum[s-1][j]+Sum[s-1][t-1]; } int main() { int row, col, i, j; cout<<"please input the row and col of the array:"<<endl; cin >> row >> col; cout<<"please input the data of the array:"<<endl; for (i=1; i<=row; i++) //输入数据; for (j=1; j<=col; j++) cin >> arr[i][j]; for (i=0; i<=row; i++) //设置边界线; Sum[i][0] = 0; for (j=0; j<=col; j++) Sum[0][j] = 0; for (i=1; i<=row; i++) // 预处理计算矩阵的部分和 for (j=1; j<=col; j++) Sum[i][j] = arr[i][j]+Sum[i-1][j]+Sum[i][j-1]-Sum[i-1][j-1]; int a, c; long long MaxSum = arr[1][1]; //初始值的设置; for (a=1; a<=row; a++) for (c=a; c<=col; c++) // 将子矩阵上下边界设为第a行和第c行,求取取最大值 { long long Tail = MatrixSum(a, 1, c, 1); //合并列; for (j=2; j<=col; j++) //按一维数组向后枚举; { Tail = max( MatrixSum(a, j, c, j), MatrixSum(a, j, c, j)+Tail); MaxSum = max(Tail, MaxSum); } } cout <<"最大的子矩阵和为:"<< MaxSum<<endl; system("pause"); return 0; }运行结果如下:
#include <iostream> #include <algorithm> using namespace std; #define LEN 1003 int arr[LEN][LEN]; long long Sum[LEN][LEN]; inline long long MatrixSum(int s, int t, int i, int j) { return Sum[i][j]-Sum[i][t-1]-Sum[s-1][j]+Sum[s-1][t-1]; } int main() { int row, col, i, j; cout<<"please input the row and col of the array:"<<endl; cin >> row >> col; cout<<"please input the data of the array:"<<endl; for (i=1; i<=row; i++) for (j=1; j<=col; j++) cin >> arr[i][j]; for (i=0; i<=row; i++) Sum[i][0] = 0; for (j=0; j<=col; j++) Sum[0][j] = 0; // 计算矩阵的部分和 for (i=1; i<=row; i++) //计算部分和; for (j=1; j<=col; j++) Sum[i][j] = arr[i][j]+Sum[i-1][j]+Sum[i][j-1]-Sum[i-1][j-1]; int a, c; long long MaxSum = arr[1][1]; // 上下边界不会跨过第n行和第1行 for (a=1; a<=row; a++) for (c=a; c<=row; c++) { // 将子矩阵上下边界设为第a行和第c行 // 左右边界不会跨过第m列和第1列 long long Tail = MatrixSum(a, 1, c, 1); for (j=2; j<=col; j++) { Tail = max(MatrixSum(a, j, c, j), MatrixSum(a, j, c, j)+Tail); MaxSum = max(Tail, MaxSum); } long long Sum = MatrixSum(a, 1, c, 1); // 左右边界会跨过第n列和第1列 long long Start = Sum; int sind = 1; for (i=2; i<=col; i++) { Sum += MatrixSum(a, i, c, i); if (Sum > Start) {Start = Sum; sind = i;} } Tail = MatrixSum(a, col, c, col); int tind = col; for (j=col-1; j>=1; j--) { Sum += MatrixSum(a, j, c, j); if (Sum > Tail) {Tail = Sum; tind = j;} } if (sind<tind && Start+Tail>MaxSum) MaxSum = Start+Tail; } cout <<"最大的子矩阵和为:"<< MaxSum<<endl; system("pause"); return 0; }扩展问题2:求3维矩阵,也就是长方体中子长方体的最大值?
#include <iostream> #include <algorithm> using namespace std; #define LEN 500 int arr[LEN][LEN][LEN]; int Sum[LEN][LEN][LEN]; inline int MaxCubeSum(int a, int b, int c, int d, int i, int j) { return Sum[b][d][j]-Sum[a-1][d][j]-Sum[b][c-1][j]-Sum[b][d][i-1]+ Sum[a-1][c-1][j]+Sum[a-1][d][i-1]+Sum[b][c-1][i-1]-Sum[a-1][c-1][i-1]; } int main() { int row, col, high, i, j, k; cout<<"please input the row, col and high of the array:"<<endl; cin >> row >> col >>high; cout<<"please input the data of the array:"<<endl; for (i=1; i<=row; i++) for (j=1; j<=col; j++) for (k=1; k<=high; k++) cin >> arr[i][j][k]; for (i=0; i<=row; i++) for (j=0; j<=col; j++) Sum[i][j][0] = 0; for (i=0; i<=row; i++) for (k=0; k<=high; k++) Sum[i][0][k] = 0; for (j=0; j<=col ; j++) for (k=0; k<=high; k++) Sum[0][j][k] = 0; // 计算长方体的部分和 for (i=1; i<=row; i++) for (j=1; j<=col; j++) for (k=1; k<=high; k++) Sum[i][j][k] = arr[i][j][k]+Sum[i-1][j][k]+Sum[i][j-1][k]+Sum[i][j][k-1]-Sum[i-1][j-1][k]-Sum[i-1][j][k-1]-Sum[i][j-1][k-1]+Sum[i-1][j-1][k-1]; int a, b, c, d; int MaxSum = arr[1][1][1]; // 限制第一维的取值范围 for (a=1; a<=row; a++) for (b=a; b<=row; b++) // 限制第二维的取值范围 for (c=1; c<=col; c++) for (d=c; d<=col; d++) { // 只剩下最后一维没有确定,利用一维部分和的方法 int Tail = MaxCubeSum(a,b,c,d,1,1); for (j=2; j<=k; j++) { int cur = MaxCubeSum(a,b,c,d,j,j); Tail = max(Tail+cur, cur); MaxSum = max(Tail, MaxSum); } } cout <<"最大的子矩阵和为:"<< MaxSum<<endl; system("pause"); return 0; }
标签:
原文地址:http://blog.csdn.net/gogokongyin/article/details/51889814