大家来看一道算法题

super_chris 2009-09-01 10:38:47
给一个整数序列,序列中数据可正可负可为零,求其和为最大的连续子序列的和?
如:
序列为 1,3,-8,2,6,-2,4,-2,1
结果为10 子序列为2,6,-2,4
只要求输出最大和。

这是一个DP问题,麻烦对DP概念清晰的同志在解答的时候说一下
这个问题的状态变量是什么,状态转移方程是什么,决策变量是什么,规划方程是什么?
谢谢!
...全文
589 点赞 收藏 57
写回复
57 条回复
切换为时间正序
请发表友善的回复…
发表回复
myouuu 2009-09-09
啊哈 ,19楼的代码是如此的优雅,顶
回复
showjim 2009-09-09
        public static int maxSum(int[] values)
{
int value = 0;
if (values != null)
{
int sum = 0;
for (int v, lv = 0, sub = 0, i = values.Length - 1; i >= 0; i--)
{
if ((v = values[i]) != 0)
{
if (v > 0)
{
if (lv < 0)
{
if ((sum += sub) < 0) sum = v;
else sum += v;
sub = 0;
}
else sum += v;
}
else
{
if (lv >= 0 && value < sum) value = sum;
sub += v;
}
lv = v;
}
}
if (sum > value) value = sum;
}
return value;
}
回复
24K純帥 2009-09-09
up,要找工作了,得看看数据结构啦
回复
super_chris 2009-09-04
[Quote=引用 52 楼 linren 的回复:]
18楼里的想法是找到以每个位置为开头时的最好情况
以这些情况作为当前状态
并且求Max,决策出用哪个位置作为开头……

19楼里的想法是找到以每个位置为结束时的最好情况
以这些情况作为当前状态
并且求Max,决策出用哪个位置作为结尾……
[/Quote]

对的 DP的时候固定一端 浮动另一端 另用一个变量来记录最优值
也就是此题的DP函数不是全局最优 而是加了条件即一端浮动一端固定的最优 全局最优通过比较间接获得
回复
qfmyztmd 2009-09-04
18 19均正解,新人受教
回复
linren 2009-09-04
18楼里的想法是找到以每个位置为开头时的最好情况
以这些情况作为当前状态
并且求Max,决策出用哪个位置作为开头……

19楼里的想法是找到以每个位置为结束时的最好情况
以这些情况作为当前状态
并且求Max,决策出用哪个位置作为结尾……
回复
nealxhf 2009-09-04
已经拜读,
从正数起始。以负数结束。
用一个sum做中间存储变量
只用循环一遍
果然正解
回复
zhenyunyuan 2009-09-03
用c写的程序,你看看吧

main()
{
int l[9]={1,3,-8,2,6,-2,4,-2,1};
int maxh =0;
int maxl =1;
int sum =1;
int maxsum=1;
int i,j;
for(i=1;i<9;i++)
{
sum=0;
for(j=i;j<9;j++)
{
sum +=l[j];
if(sum >maxsum)
{
maxsum=sum;
maxh=i;
maxl=j;
}
}
}

for(i=maxh;i<=maxl;i++)
{
printf("%d ",l[i]);
}

getch();
}
回复
super_chris 2009-09-03
[Quote=引用 48 楼 g_idea 的回复:]
http://blog.csdn.net/g_idea/archive/2009/09/03/4514913.aspx
[/Quote]已经拜读 这个体现得很明显 不如贴过来
回复
piqio379 2009-09-03
#include "stdio.h"
#define N 9
main()
{
int c[N+1];
int a[N];
int d[N+1];
int i;

for ( i=0;i<=N;i++)
c[i]=d[i]=0;

for ( i=1;i<N;i++)
scanf("%d ",&a[i]);

for (i=1;i<=N;i++)
{ if (d[i-1]+a[i]<=0)
{
d[i]=0;
c[i]=c[i-1];
}
else
{
d[i]=d[i-1]+a[i];
if (d[i]<=c[i-1])
c[i]=c[i-1];
else
c[i]=d[i];
}
}
for (i=1;i<=N;i++)
printf("%d ",c[i]);
}
回复
丈八涯 2009-09-03
http://blog.csdn.net/g_idea/archive/2009/09/03/4514913.aspx
回复
morilasi 2009-09-02
这也是我第二次回答这样的问题了。。
#include <iostream>
using namespace std;
int arr[100];

int
main(void)
{
int len=0;
while(cin>>arr[len++]);
int globalmax=0; //记录最大值
int suffixmax=0; //记录以当前值结束的序列的最大值
for(int i=0;i!=len;i++)
{
suffixmax+=arr[i];
if(suffixmax>globalmax)
globalmax=suffixmax;
if(suffixmax<0) //如果当前最大值小于0,则该序列一定不在结果中,去置suffixmax为0
suffixmax=0;
}
cout<<globalmax<<endl;
}
回复
super_chris 2009-09-02
[Quote=引用 18 楼 linren 的回复:]
的确是可以用动态规划来做……

【程序】
C/C++ code#include<stdio.h>
#include<stdlib.h>
#include<string.h>#define SIZE 9int a[SIZE]={1,3,-8,2,6,-2,4,-2,1};void fun(int*a,int len){int i,j;int*b;int ia,ib,ic;int x,y,z;
b=(int*)malloc(sizeof(int)*(len+2)*len);
memset(b,0,sizeof(int)*(len+2)*len);
ic=-1;for(i=0;i<len;i++){
ia=0;ib=-1;for(j=i;j<len;j++){
ia+=a[j];if(ib==-1||ia>=ib){
ib=ia;x=j;if(ic==-1||ib>=ic){
ic=ib;z=i;
}
}
}
y=x-i+1;*(b+(len+2)*i)=ib;*(b+(len+2)*i+1)=y;for(j=0;j<y;j++){*(b+(len+2)*i+j+2)=i+j;
}
}for(i=0;i<*(b+(len+2)*z+1);i++) printf("%d,",a[*(b+(len+2)*z+i+2)]);
printf("\nsum=%d\n",*(b+(len+2)*z));
}int main(){
fun(a,SIZE);return0;
}
【运行结果】
Assembly code2,6, -2,4,
sum=10
Press any key to continue

【说明】
如果选中了某个位置作为开头……
那么以这个位置得到的最大子序列和的情况就是可以唯一确定的……

比如说:
1,3,-8,2,6,-2,4,-2,1
选中第5位作为开头
6=6
6-2=4
6-2+4=8
6-2+4-2=6
6-2+4-2+1=7
最好的情况为:[6, -2, 4]

把每个位置的最好情况记录下来……
然后选出其中的最好情况就是答案了……

属于只决策了一次的动态规划……
[/Quote]

请问决策了那一次?
回复
super_chris 2009-09-02
我先说说我理解的DP思想吧

有不对地方还请指正

DP解决的是多阶段决策问题,解决的手段是递推,在递推到某个阶段时,并不能确定该阶段的各种决策哪个可以发展为全局最优,这个依赖于尚未递推的阶段,因此要将这些中间结果存储起来。但是对于该阶段各个决策(即该阶段各个状态)所代表的子问题,都应该在该阶段有一个完整的总结,这样对于下一阶段的递推可以完全独立依赖于本阶段,而不依赖更以前的阶段,本阶段各种策略的总结也是对于下一阶段进行递推的依据所在。

这是我理解的DP思想

可是这个问题的解决方法我却看不到这种思想。

我试着如此考虑:

这个问题的阶段数就是序列的长度,每个阶段要做的决策只有两种,1.将此数加入序列;2.放弃此数,从下一数字从新开始。而这两个策略孰优孰劣,目前还不得知,还要依赖其后面的序列情况。因此应该将两种中间结果都存储起来。

我再想想。
回复
xiaoyu821120 2009-09-02
这个是我最近看到的第二次同样的问题了
http://topic.csdn.net/u/20090820/15/69736ad0-fd3c-45c9-88fd-30489d206250.html
回复
linren 2009-09-02
[Quote=引用 19 楼 litaoye 的回复:]
再次转帖一个别人的程序,加了注释

int MaxSum(int n,int *a)
{
int sum = a[0], b=0;
for(int i=0;i <n;i++)
{
//这部分体现了DP的思想,>0的才算是最优子结构
if(b>0)
b += a[i];
else
b = a[i];

if(b>sum)
sum=b;
}
return sum;
}

[/Quote]
这个办法比我想到的好多了^_^……

稍微修改了一下:
void MaxSum(int *a,int n)
{
int sum = a[0], b=0;
int x=0,y=0,z=0;
for(int i=0;i <n;i++)
{
//这部分体现了DP的思想,>0的才算是最优子结构
if(b>0) b += a[i];
else{
b = a[i];x=i;
}

if(b>sum){
z=x;sum=b;y=i;
}
}

for(i=z;i<=y;i++) printf("%d, ",a[i]);
printf("\nsum=%d\n",sum);
}
回复
绿色夹克衫 2009-09-02
再次转帖一个别人的程序,加了注释

int MaxSum(int n,int *a)
{
int sum = a[0], b=0;
for(int i=0;i <n;i++)
{
//这部分体现了DP的思想,>0的才算是最优子结构
if(b>0)
b += a[i];
else
b = a[i];

if(b>sum)
sum=b;
}
return sum;
}
回复
linren 2009-09-02
的确是可以用动态规划来做……

【程序】
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 9
int a[SIZE]={1,3,-8,2,6,-2,4,-2,1};

void fun(int *a,int len){
int i,j;
int *b;
int ia,ib,ic;
int x,y,z;
b=(int*)malloc(sizeof(int)*(len+2)*len);
memset(b,0,sizeof(int)*(len+2)*len);
ic=-1;
for(i=0;i<len;i++){
ia=0;ib=-1;
for(j=i;j<len;j++){
ia+=a[j];
if(ib==-1||ia>=ib){
ib=ia;x=j;
if(ic==-1||ib>=ic){
ic=ib;z=i;
}
}
}
y=x-i+1;
*(b+(len+2)*i)=ib;
*(b+(len+2)*i+1)=y;
for(j=0;j<y;j++){
*(b+(len+2)*i+j+2)=i+j;
}
}

for(i=0;i<*(b+(len+2)*z+1);i++) printf("%d, ",a[*(b+(len+2)*z+i+2)]);
printf("\nsum=%d\n",*(b+(len+2)*z));
}

int main(){
fun(a,SIZE);
return 0;
}

【运行结果】
2, 6, -2, 4,
sum=10
Press any key to continue


【说明】
如果选中了某个位置作为开头……
那么以这个位置得到的最大子序列和的情况就是可以唯一确定的……

比如说:
1,3,-8,2,6,-2,4,-2,1
选中第5位作为开头
6=6
6-2=4
6-2+4=8
6-2+4-2=6
6-2+4-2+1=7
最好的情况为:[6, -2, 4]

把每个位置的最好情况记录下来……
然后选出其中的最好情况就是答案了……

属于只决策了一次的动态规划……
回复
super_chris 2009-09-02
[Quote=引用 15 楼 arong1234 的回复:]
我没这个能力,我只是恰好知道一种没有所谓状态变量的动态规划方法而已。看到很多人一说DP就想到状态变量和状态转移方程,我想这很可能是错误的。
如果要形象的,阁下要找的是你的老师和课本
引用 14 楼 super_chris 的回复:
引用 12 楼 arong1234 的回复:
可能我说的不对,不过动态规划的方法我记得有很多的,不是每种技术都使用到诸如你说的状态变量之类的概念的。例如我记得有个叫单纯型法的算法,就不存在你说的这些。我估计这是把DP公式化导致的误解
建议大家还是务虚的理解DP,不要形而上学的理解它

引用 11 楼 super_chris 的回复:
引用 10 楼 hxyokokok 的回复:
那个填表的不行,这个题的标准解法就是O(n)的。。。
对 DP是O(N)的
可是我就是搞不懂 这个解法哪里体现DP了 概念不清晰

那请你形象化地解释一下DP的思想 thx

[/Quote]书本一点都不形象啊

现在我觉得书本上的例子 和我遇到的DP问题 我找不到它们的共同模式
回复
请高手写算法
回复
发动态
发帖子
数据结构与算法
创建于2007-08-27

3.2w+

社区成员

数据结构与算法相关内容讨论专区
申请成为版主
社区公告
暂无公告