这道题是个二维数组的,我们看看:如果有一个一维数组a[n],如何找出连续的一段,使其元素之和最大呢?
例如:int a[]= {1,2, -3, 4, -2, 5,-3,-1, 7,4, -6 }; max=14。
1.穷举法(有三层循环,所以n很大时不能使用这种方法。)
int main()
{
int a[]={1 ,2, -3, 4, -2, 5 ,-3 ,-1, 7,4, -6 };
int n=11,i,j,k,max=-INF;
int sum = 0;
for(i=0; i<n; i++)
{
for(j=0; j<=i; j++)
{
sum = 0;
for(k=j; k<=i; k++)
sum += a[k];
if(sum > max) max = sum;
}
}
cout<<max<<endl;
return 0;
}
2、带记忆的递推法
int main()
{
int a[]= {1,2, -3, 4, -2, 5,-3,-1, 7,4, -6 };
int record[20],sum=0,n=11;
int i,j,max;
record[0] = 0;
for(i=1; i<=n; i++)
record[i] = record[i-1] + a[i]; //用record记录a[i]前i个的和
max = -INF;
for(i=1; i<=n; i++)
{
for(j=0; j<i; j++)
{
sum = record[i] - record[j];
if(sum > max) max = sum;
}
}
cout<<max<<endl;
return 0;
}
3、动态规划
分析一下最优子结构,若想找到n个数的最大子段和,那么要找到n-1个数的最大子段和,这就出来了。我们用b[i]来表示a[0]...a[i]的最大子段和,b[i]无非有两种情况
(1)最大子段一直连续到a[i]
(2)以a[i]为首的新的子段。
由此我们可以得到b[i]的状态转移方程:
b[i]=max{ b[i-1]+a[i],a[i] }
最终我们得到的最大子段和为max{ b[i], 0<=i<n},Code:
int MaxSubArray(int a[],int n)
{
int i,b = 0,sum = 0;
for(i = 0;i < n;i++)
{
if(b>0) // 若a[i]+b[i-1]会减小
b += a[i]; // 则以a[i]为首另起一个子段
else
b = a[i];
if(b > sum)
sum = b;
}
return sum;
}
int main () {
int a[]= {1,2, -3, 4, -2, 5,-3,-1, 7,4, -6 };
int ans = MaxSubArray(a,11);
cout<<ans<<endl;
return 0;
}
于是乎这道题中二维数组的每一列也可以看做一个一维数组。结合上面的1和3:
#include <iostream>
#include <cstring>
using namespace std;
const int INF = 0x3f3f3f3f;
int maxsub(int a[],int n)
{
int i,max=-INF,b=0;
for(int i=0; i<n; i++)
{
if(b>0) b+=a[i];
else b=a[i];
if(b>max) max = b;
}
return max;
}
int main()
{
int n,m,res,max=-INF;
int f[100][100],arr[100];
cin>>n>>m;
for(int i=0; i<n; i++)
for(int j=0; j<m; j++)
cin>>f[i][j];
for(int i=0; i<n; i++)
{
memset(arr,0,sizeof(arr));
for(int j=i; j<n; j++)
{
for(int k=0;k<m; k++)
arr[k]+=f[j][k];
res = maxsub(arr,m);
if(max<res) max = res;
}
}
/*for(int i=0; i<n; i++)
{
memset(arr,0,sizeof(arr));
for(int j=i; j<n; j++)
{
for(int k=m-1;k>=0; k--)
arr[k]+=f[j][k];
res = maxsub(arr,m);
if(max<res) max = res;
}
}*/
cout<<max<<endl;
return 0;
}