首先定义两个数组a[i]和dp[i],a[i]用来存放当前组的元素,dp[i]根据动态规划的英文dynamic programming的首字母来命名,这里的dp[i]的存储的数据为以i结尾的最大连续和序列的和。而要求的最大连续和就是dp[i]中最大的那个元素。
给出递推公式 dp[i] = max(dp[i-1]+a[i],a[i])
理解该公式,以i结尾的最大连续和序列只有两种情况:第一种就是a[i]本身,a[i]本身以i开始并以i结束,满足以i结尾;第二种就是以i-1结尾的最大连续和序列再加上a[i],肯定满足以i结尾,至于从哪里开始需要进一部考察。
但是问题似乎已经得到了解答,由dp[i-1]可以得到dp[i](a[i]是自己输入的数据,已知),有了递推公式只要知道第一项dp[0]即可,而dp[0]=a[0],因为以0结尾的只有一个数字,就是a[0]。
给出代码:
#include<iostream>
using namespace std;
const int N = 100005;
int main()
{
/*
t,n的意义如题中所述,
s表示start的首字母,用来记录开始位置的下标,
e表示end的首字母,用来记录结束位置的下标
i用来做循环标记
m为max的首字母,记录最大连续和序列的和
ps为position_start的首字母,用来存放每一个dp[i]对应的序列的开始位置
pe为position_end的首字母, 用来存放每一个dp[i]对应的序列的结束位置
c为case的首字母,用来记录是第几个case
*/
int t,n,s,e,i,m,ps,pe,c=1;
int a[N],dp[N]; //a数组存放当前case中的元素,dp数组用来记录以i为下标的最大连续和序列的和
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
s=e=ps=pe=0;m=dp[0]=a[0]; //i=0时初始化
for(int i=1;i<n;i++) //i从1开始
{
/*
if...else语句用来初始化dp数组
*/
if(dp[i-1]+a[i]>=a[i]) {
dp[i]=dp[i-1]+a[i];
ps=ps; //跟新起始位置,由于值不变,可以注释掉该语句,这里只是为了清楚的表示思维逻辑
pe=i; //跟新结束位置
}
else{
dp[i]=a[i];
ps=i; //跟新起始位置
pe=i; //跟新结束位置
}
if(dp[i]>m){
m=dp[i];
s=ps;
e=pe;
}
}
printf("Case %d:\n%d %d %d\n",c++,m,s+1,e+1);
if(t) printf("\n");
}
}
当然可以定义结构题mydp如下:
struct{
int ms; //记录最大连续和
int ps; //记录起始位置
int pe; //记录结束位置
}mydp;
typedef struct mydp *dp;
将每一个以i结尾的最大连续和,以及该和的起始位置和结束位置都封装在一个结构体里面,就能够更好的理解动态规划是如何解决该问题的。
以上是来自一个经过两天思考才把hdu acm 1003吃透的一个菜鸡的挣扎,希望能帮到米娜桑。
最后再提供另外一种解决思路,对于了解动态规划的人来说简直愚蠢的解答,即便如此,让自己一直思考总是一种不错的生活学习态度。简单说下思路,假设每次输入一个数据,在笛卡尔坐标系就记录sum,所谓的最大连续和序列就是笛卡尔坐标系中连续的高度差最大的那个的高度差的值,起始位置和结束位置,就是在该曲线(也可能只是一个点)的两个端点。
(原谅我找不到代码了 (o.o)...)