求解最大子段和
原题链接
求解最大子段和有三种方法:
- 遍历数组,在遍历的过程中更新比较最大和
- 分治法,考虑最大子段出现在左边、右边、以及中间的情形
- 动态规划法,其中dp[j]是以j为结尾的子段和,由此可列出状态转移方程dp[j]=max(dp[j-1]+a[j],a[j]),这题还需要输出最大子段的始末元素,设置一个start数组,start[j]保存以j为结尾的子段和起始位置
ps:以下为遍历方法与动态规划法的AC代码
解法一(遍历)
#include <iostream>
using namespace std;
int main()
{
int N, a[10000], low=0, high=0, maxsum=0;
int nowlow, nowhigh, nowsum;
bool flag = false;
cin >> N;
for (int i=0; i<N; i++)
{
cin >> a[i];
if (a[i] >= 0)
flag = true;
}
if (flag == false)
{
cout<<0<<" "<<a[0]<<" "<<a[N-1];
return 0;
}
nowlow=0,nowhigh=0,nowsum=0;
while(nowhigh != N)
{
if (nowsum+a[nowhigh] >= 0)
{
nowsum += a[nowhigh];
if (nowsum > maxsum)
{
low = nowlow;
high = nowhigh;
maxsum = nowsum;
}
}
else
{
nowlow = nowhigh+1;
nowsum = 0;
}
nowhigh++;
}
if (maxsum == 0)
cout<<maxsum<<" "<<0<<" "<<0;
else
cout<<maxsum<<" "<<a[low]<<" "<<a[high];
return 0;
}
解法3(动态规划)
#include <iostream>
#include <cstdio>
using namespace std;
const int maxk = 10001;
int main()
{
int K, a[maxk], dp[maxk], start[maxk];
scanf("%d",&K);
for (int i=1; i<=K; i++)
scanf("%d",&a[i]);
dp[1] = a[1];
start[1] = 1;
for (int i=2; i<=K; i++)
{
if (dp[i-1]+a[i] > a[i])
{
dp[i] = dp[i-1]+a[i];
start[i] = start[i-1];
}
else
{
dp[i] = a[i];
start[i] = i;
}
}
int maxdp = dp[1],maxi = 1;
for (int i=2; i<=K; i++)
{
if (dp[i]>maxdp)
{
maxdp = dp[i];
maxi = i;
}
}
if (maxdp < 0)
printf("0 %d %d",a[1], a[K]);
else
printf("%d %d %d",maxdp, a[start[maxi]], a[maxi]);
return 0;
}
end