先介绍一下什么是最大子段和:确定每个子段和开始的位置,分别为第一个,第二个,第三个…第N个,然后计算从这个位置开始到这个位置之后的每个位置的子段和,更新记录最大的子段和。简单来讲有个数组属于实数,连续的子段那一段的数值最大
一下是最简单的办法 菜鸡只会暴力
#include <iostream>
using namespace std;
int MaxSum(int n,int *a,int &besti,int &bestj)
{
int sum = 0;
for(int i = 0;i < n;i++)
{
int thissum = 0;
for(int j = i;j < n;j++)
{
thissum += a[j];
if(thissum > sum)
{
sum = thissum;
besti = i;
bestj = j;
}
}
}
return sum;
}
int main()
{
int n = 6;
int a[] = {-2,11,-4,13,-5,-2};
int besti;
int bestj;
cout<<"最大子段和为:"<<MaxSum(n,a,besti,bestj)<<endl;
cout<<"起始位置:"<<besti<<endl<<"终止位置:"<<bestj;
return 0;
}
分治法的利用
#include<iostream>
using namespace std;
int MaxSubSum(int *a,int left,int right)
{
int sum = 0;
if(left == right)
sum = a[left]>0?a[left]:0;
else
{
int center = (left + right)/2;
int leftsum = MaxSubSum(a,left,center);
int rightsum = MaxSubSum(a,center+1,right);
int s1 = 0;
int lefts = 0;
for(int i = center;i >= left;i--)
{
lefts += a[i];
if(lefts > s1)
s1 = lefts;
}
int s2 = 0;
int rights = 0;
for(int i = center+1;i <= right;i++)
{
rights += a[i];
if(rights > s2)
s2 = rights;
}
sum = s1 + s2;
if(sum < leftsum)
sum = leftsum;
if(sum <rightsum)
sum = rightsum;
}
return sum;
}
int MaxSum(int n,int *a)
{
return MaxSubSum(a,0,n-1);
}
int main()
{
int n = 6;
int a[] = {-2,11,-4,13,-5,-2};
cout<<"最大子段和为:"<<MaxSum(n,a)<<endl;
return 0;
}
dp
#include<iostream>
using namespace std;
int MaxSum(int n,int *a,int &besti,int &bestj)
{
//b表示的是以元素a[i]为结尾的最大子段和
int sum = -1, b = 0,flag;
for(int i = 0;i < n;i++)
{
if(b > 0) b += a[i];
else
{
b = a[i];
flag=i;
}
if(b > sum)
{
sum = b;
besti=flag;
bestj=i;
}
}
return sum;
}
int main()
{
int n = 6;
int a[] = {-2,11,-4,13,-5,-2};
int besti=0,bestj=n-1;
int sum=MaxSum(n,a,besti,bestj);
if(sum==-1) sum=0;
cout<<"最大子段和为:"<<sum<<endl;
cout<<"初始位置:"<<besti<<"末尾位置:"<<bestj<<endl;
return 0;
}
略化简之后的算法
#include<iostream>
using namespace std;
int a[100];
int maxsum(int n) {
int b=0,sum=-1;
for(int i=0; i<n; i++) {
if(b>0)b+=a[i];
else b=a[i];
if(b>sum) sum=b;
}
return sum;
}
int main() {
int n;
cin>>n;
for(int i=0; i<n; i++) cin>>a[i];
int ans=maxsum(n);
cout<<ans<<endl;
return 0;
}
最大子阵和
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int biggest_field(int a[],int n); //求最大子段和函数
int search(int jz[100][100],int n); //查询最大子矩阵函数
void input_jz(); //输入原始矩阵函数
int n,jz[100][100];//原始矩阵长度、原始矩阵
int main() {
cin>>n; //输入原始矩阵长度
input_jz(); //输入原始矩阵
int answer=search(jz,n); //查询最大子矩阵,将结果保存在answer中。
cout<<endl<<"answer:"<<answer<<endl; //输出结果
return 0;
}
void input_jz() {
for (int i=1; i<=n; i++) {
for (int j=1; j<=n; j++) {
cin>>jz[i][j];
}
}
}
int search(int jz[100][100],int n) {
int sum=0,vals[100],k,i,j;
for (i=1; i<=n; i++) { //每个行数的起点行
memset(vals,0,sizeof(vals)); //初始化vals数组的值为0
//把第i行到第j行相加,对每一次相加求出最大值
for (j=i; j<=n; j++) {
for (k=1; k<=n; k++) vals[k]+=jz[j][k];
int val=biggest_field(vals,k); //传入相加后组成的数组(子段),接着求每一次相加的最大
if (sum<val) sum=val;
}
}
return sum; //返回最终结果
}
int biggest_field(int a[],int n) { //一维数组a是一个子段
int b=0,sum=a[1];
for (int i=1; i<=n; i++) {
if (b>0) b+=a[i];
else b=a[i];
if (b>sum) sum=b;
}
return sum; //返回最大子段和
}