题目来源:HDU 1231
简单题目分析:
求最大子段和,及该子段的首尾元素。
在最基础的最大子段和问题的基础上,再多维护一下首尾元素即可,对于动态规划数组dp[i]的含义是以数组中i号下标结尾的子序列的最大值,因此状态转移方程为:
dp[i]=max(dp[i-1]+temp[i],temp[i]) 其中temp数组存储的是整个序列
对于每个dp[i],显然末尾元素的下标即为i,所以我们只需要维护首元素下标即可。我们可以注意到,如果dp[i-1]非负,那么首元素是不需要改变的,即当前的最大子段和只需要前一个状态的子段和再加上当前下标的数组元素(因为前一个子段和非负),否则的话,前一个子段和是负数,那么直接舍弃从当前下标重新开始寻找最大子段,首元素的下标就会维护为当前元素的下标。
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstdio>
#include <math.h>
using namespace std;
const int MAXN=10000+5;
struct dp
{
int dp; //dp数组
int head; //记录最大子段和的起始下标
int tail; //记录最大子段和的结束下标
}temp[MAXN];
int N;
int s[MAXN];
bool cmp(dp a,dp b)
{
if(a.dp==b.dp)
return a.head<b.head;
else
return a.dp>b.dp;
}
int main()
{
while(~scanf("%d",&N) && N!=0)
{
int i,cnt=0;
for(i=1;i<=N;++i)
{
scanf("%d",&s[i]);
if(s[i]<0)
cnt++;
}
if(cnt==N)
printf("0 %d %d\n",s[1],s[N]);
else
{
temp[1].dp=s[1]; //dp初始化
temp[1].head=temp[1].tail=1;
for(i=2;i<=N;++i)
{
temp[i].dp=max(temp[i-1].dp+s[i],s[i]); //状态转移方程
if(temp[i-1].dp<0)
temp[i].head=i;
else
temp[i].head=temp[i-1].head;
temp[i].tail=i;
}
sort(temp+1,temp+1+N,cmp);
printf("%d %d %d\n",temp[1].dp,s[temp[1].head],s[temp[1].tail]);
}
}
return 0;
}