题目大意:
给出测试组数,第一行是测试数据的个数,然后是每个测试数据。
输出要求,输出连续子序列最大和,并且输出这个连续子序列的起始位置和终止位置。
思路:
每个数的选择只有两种,加或者不加,对吧?加的话就更新子序列下标,不加的话就重置。
每次加或者不加都会产生一种状态。每次只需要决策加或者不加,所有的最优决策就组成了最优解。
为了方便大家理解,首先我们来给出一组数据:
5 1 2 3 -6 6
也就是说 有 5 个数,分别为 1 2 3 -6 6
然后求出他的最大连续子序列的和。
开始 sum = 0 。 左边是加上下个数,右边是不加下个数。 枝点是 sum 的值。
begin
/ \
1 0
/ \ / \
3 0 2 0
/ \ / \ / \ / \
6 0 3 0 5 0 3 0
/ \ / \ / \ / \ / \ / \ / \ / \
0 0 -6 0 - 3 0 -6 0 -1 0 -6 0 -3 0 -6 0
最后一层就不写了。。。
注意看,你们发现了什么吗?
第一层, 1 和 0
从 1 走下去肯定比从 0 走下去得到的和大。
第二层 从 3 走下去得到的和 肯定也是最大的,
所以建树的过程就可以这样简化 :
begin
/ \
1 0
/ \
3 0
/ \
6 0
/ \
0 0
/ \
6 0
由此我们可以看出最大值为 6 ,那么,怎么写程序模拟这个建树的过程呢?
int sum,maxsum,first,last;
sum=0;
maxsum=-1001;
first=1;
for (i=1;i<=n;i++)
{
sum += a[i];
if (sum > maxsum)
{
maxsum=sum;
last=i;
}
if (sum <0)
{
sum=0;
first=i+1;
}
}
上面的代码,可以读一下。每次都将值加入进来,如果 sum < 0 就更新数据,如果比之前的大 就更新最大值并且记录下标。
感想:
好了,这个题看了好久,上面是我的一些见解,希望有助于大家理解动态规划,可能有的人要问 了,这个也是动态规划吗?怎么没有状态转移方程呢?
其实吧,动态规划又何尝不是一种思想呢?非要有状态转移方程吗?
不见得。(或许是我还刚接触 dp 在胡言乱语。但是希望,上面的东西有助于你们理解 dp )
AC代码:
#include
#include
using namespace std;
int main()
{
int j,i,k,n,m,t;
int a[100002];
scanf("%d",&t);
for (j=1;j<=t;j++)
{
scanf("%d",&n);
for (i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
int sum,maxsum,first,last;
sum=0;
maxsum=-1001;
first=1;
for (i=1;i<=n;i++)
{
sum += a[i];
if (sum > maxsum)
{
maxsum=sum;
last=i;
}
if (sum <0)
{
sum=0;
first=i+1;
}
}
printf("Case %d:\n%d %d %d\n",j,maxsum,first,last);
if (j!=t)
{
printf("\n");
}
}
return 0;
}