游泳圈的最大子矩阵和
Description
二维数组首尾相连,上下也相连,像个游泳圈或轮胎,又如何求最大子矩阵和?
如游泳圈展开成3行3列的二维矩阵: -18 10 7 1 -20 2 1 38 -2 那么最大的子矩阵和为:10+7+38-2=53 2 10 7 1 -20 2 1 38 -2 那么最大的子矩阵和为:10+7+2+38-2+1=56
Input
游泳圈展开成平面数组,第一行是行数m和列数n,第二行至第m+1行是数组数值,每行n个数。
Output
最大的子矩阵和
Sample Input
3 3 2 10 7 1 -20 2 1 38 -2
Sample Output
56
=====================================================================
我要说的是,这个题目曾经是各大IT公司的一个面试题,可想它是多么的经典。作为学习交流,希望可以给需要的人带去一丝灵感。。以下我将按个人想法分析一下该题目:
游泳圈的最大子矩阵和其实就是把平面上下相连和左右相连。不管先连那边都一样的,一样是O(n^3)。有两种方法:先把游泳圈剪开成平面(随便找一条横边和一条竖边即可),然后原问题等价于把4个这样的平面拼在一起找不超过一个平面大小的最大子矩阵。先用O(n^2)空间转换为1维的问题,枚举上下边界,用一维的方法用单调队列求解。第二种方法比较蛋疼:把游泳圈开一边形成一个环(横的竖的出来结果都一样),假设结果不会越过剪的那条边,于是又是转化为一维的循环数组了。。如果结果越边,还是枚举上下边界转为一维数组的最小子段和。好麻烦,还是第一种方法好。
为了方便编程,我选择第一种方法来解决这个题目。
以下是核心代码(仅供参考学习,请勿直接复制提交):
#include "stdio.h"
#include
int MaxSum(int n,int* a);
int MaxSum2(int m, int n, int a[][101]);
int main()
{
int m,n;
scanf("%d%d",&m,&n);
int temp[101][101];
int result[10000];
int s[202][202];
int i,j,p,q;
memset(temp,0,sizeof(temp));
memset(s,0,sizeof(s));
memset(result,0,sizeof(result));
//输入二维数组
for( i=1; i<=m; i++)
for( j=1; j<=n; j++)
{
scanf("%d",&s[i][j]);
s[i][n+j] = s[i][j];
s[m+i][j] = s[i][j];
s[m+i][n+j] = s[i][j];
}
int r =0;
for( i=0; i
for( j=0; j
{
for( p=1; p<=m; p++)
{
for(q=1; q<=n; q++)
temp[p][q] = s[p+i][q+j];
}
result[r++] = MaxSum2(m,n,temp); //记录各种情况下的最大子矩阵和
}
int maxresult = result[0]; //从各种情况下的最大子矩阵和中找出最大的值
for (i=1; i
{
if(maxresult < result[i])
maxresult = result[i];
}
printf("%d\n",maxresult);
return 0;
}
//用动态规划算法计算“最大子段和问题”,对应于一维数组
int MaxSum(int n,int* a)
{
int sum=0,b=0;
for (int i=1;i<=n;i++)
{
if (b>0) b+=a[i];
else b=a[i];
if (b>sum) sum=b;
}
return sum;
}
int MaxSum2(int m, int n, int a[][101])
{
int sum=0;
int b[101];
int i,j,k,p,t1=0,t2=0;
memset(b,0,sizeof(b)); //内存空间初始化
for ( i=1; i<=m; i++)
{
int flag_m = m , flag_n = n;
for( k=1; k<=2*n; k++)
b[k]=0;
for ( j=i; j < flag_m + i; j++)
{
t1 = j>m? j-m : j;
for( k=1; k <=n ; k++)
{
t2 = k>n? k-n : k;
b[k] += a[t1][t2];
}
int max = MaxSum(2*n,b);
if(max>sum) sum = max;
}
}
return sum;
}