主题:请问这道DP题该怎么做?
apeng332
[专家分:0] 发布于 2010-04-16 10:20:00
题目是:给定一个数列,如何在此数列的所有单调递增子数列里找出所有项和最大的一个?
输入是若干个数,输出是满足条件的子数列的所有项之和。
例如:
input:
5 3 4 9 2 3 4 5 6 11 9
output:
31 【31=2+3+4+5+6+11】
请问对于这道题有什么好的算法没有?我想了N久没想出来,哪位大侠给个思路或贴出程序
回复列表 (共7个回复)
沙发
mywaylgh [专家分:210] 发布于 2010-04-16 14:21:00
这个问题有必要用动态规划么.......
[code=c]
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i,j,k,m,n;
int *seq,*trace,*max_trace;
int sum_subseq,max_subseq,len_max;
printf("Number of the sequence:");
scanf("%d\n",&n);
seq = (int *)malloc(n*sizeof(int));
trace = (int *)malloc(n*sizeof(int));
max_trace = (int *)malloc(n*sizeof(int));
for (i=0;i<n ;i++ )
scanf("%d",seq+i);
i=1;
max_subseq = seq[0];
len_max = 0;
max_trace[0]=seq[0];
while(i<n)
{
m=0;
sum_subseq=seq[i-1];
trace[m++]=seq[i-1];
for (j=i;j<n ;j++ )
if (seq[j]<=seq[j-1])
break;
else
{
trace[m++]=seq[j];
sum_subseq += seq[j];
}
if (sum_subseq>max_subseq)
{
for (k = 0;k<m ;k++ )
max_trace[k] = trace[k];
len_max = m;
max_subseq = sum_subseq;
}
i=i+m;
}
printf("Max sum: ");
printf("%d = %d",max_subseq,max_trace[0]);
for (i=1;i<len_max ;i++ )
printf(" + %d",max_trace[i]);
return 0;
}
[/code]
板凳
overfly [专家分:3230] 发布于 2010-04-16 14:53:00
5 3 4 9 2 3 4 5 6 11 9
从头开始查找
第一次,从5开始查找,发现5 > 3时停止,计算递增值为5,记录
第二次,从3开始查找,发现9 > 2时停止,计算递增值为3+4+9,大于5,删除5,记录3+4+9(替换)
第三次,从2开始查找,发现11 > 9时停止,计算递增值2+3+4+5+6+11,大于
3+4+9,删除3+4+9,记录2+3+4+5+6+11(替换)
第四次,从9开始查找,发现查找到结尾,计算递增值为9,小于2+3+4+5+6+11,删除9(不替换),得出单调递增最大值为2+3+4+5+6+11
每次查找的起始位置和记录是关键
3 楼
PP_make [专家分:60] 发布于 2010-04-16 22:33:00
基本上都大同小异,仅供参考:
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int *p1,*p2;
int i,j,n,count;
int sum1,sum2;
printf("请输入要输入数的个数:");
scanf("%d",&n);
p1 = (int*)malloc(n*sizeof(int));
p2 = (int*)malloc(n*sizeof(int));
for(i=0;i<n;i++)
scanf("%d",p1+i);
i=j=sum2=0;
while(i<=n)
{
if(p1[i]<=p1[i+1])
{
for(sum1=0;p1[i]<=p1[i+1];)
{
p2[j]=p1[i];
sum1+=p2[j];
i++;
j++;
}
sum1+=p1[i];
}
else{
i++;
count++;
}
if(sum2<=sum1)
sum2=sum1;
}
printf("%d\n",sum2);
return 0;
}
// 11
// 5 3 4 9 2 3 4 5 6 11 9
4 楼
apeng332 [专家分:0] 发布于 2010-04-18 22:15:00
[quote]5 3 4 9 2 3 4 5 6 11 9
从头开始查找
第一次,从5开始查找,发现5 > 3时停止,计算递增值为5,记录
第二次,从3开始查找,发现9 > 2时停止,计算递增值为3+4+9,大于5,删除5,记录3+4+9(替换)
第三次,从2开始查找,发现11 > 9时停止,计算递增值2+3+4+5+6+11,大于
3+4+9,删除3+4+9,记录2+3+4+5+6+11(替换)
第四次,从9开始查找,发现查找到结尾,计算递增值为9,小于2+3+4+5+6+11,删除9(不替换),得出单调递增最大值为2+3+4+5+6+11
每次查找的起始位置和记录是关键[/quote]
这样考虑并不对啊 ,你只是考虑了连续位的项和,如果离散的话可能结果有误了,你跟1楼的程序的算法是完全一样的,你看一下这个例子,如果输入的是3 4 2 4 9,理论上输出应该是16 【就是3+4+9】,但是你的算法给出的结果是2+4+9,你看看是不是?
不过很感谢你的提示,我按你给的这种思路想想,应该会有解决办法
5 楼
apeng332 [专家分:0] 发布于 2010-04-18 22:17:00
[quote]
这个问题有必要用动态规划么.......
[code=c]
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i,j,k,m,n;
int *seq,*trace,*max_trace;
int sum_subseq,max_subseq,len_max;
printf("Number of the sequence:");
scanf("%d\n",&n);
seq = (int *)malloc(n*sizeof(int));
trace = (int *)malloc(n*sizeof(int));
max_trace = (int *)malloc(n*sizeof(int));
[/code][/quote]
你的算法跟二楼的一样,可是运行起来结果有误啊,
例如输入的是3 4 2 4 9,理论上输出应该是16 【就是3+4+9】,但是你的code给出的结果是2+4+9,对吧?不过很感谢你和2楼的程序和算法,我按你们给的这种思路想想,应该会有解决办法
6 楼
apeng332 [专家分:0] 发布于 2010-04-18 22:19:00
[quote]基本上都大同小异,仅供参考:
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int *p1,*p2;
int i,j,n,count;
int sum1,sum2;
printf("请输入要输入数的个数:");
scanf("%d",&n);
p1 = (int*)malloc(n*sizeof(int));
p2 = (int*)malloc(n*sizeof(int));
[/quote]
你的code我没读,但是拷下来运行一下,发现结果有点问题,你再看看吧
7 楼
overfly [专家分:3230] 发布于 2010-04-19 08:20:00
[quote][quote]5 3 4 9 2 3 4 5 6 11 9
从头开始查找
第一次,从5开始查找,发现5 > 3时停止,计算递增值为5,记录
第二次,从3开始查找,发现9 > 2时停止,计算递增值为3+4+9,大于5,删除5,记录3+4+9(替换)
第三次,从2开始查找,发现11 > 9时停止,计算递增值2+3+4+5+6+11,大于
3+4+9,删除3+4+9,记录2+3+4+5+6+11(替换)
第四次,从9开始查找,发现查找到结尾,计算递增值为9,小于2+3+4+5+6+11,删除9(不替换),得出单调递增最大值为2+3+4+5+6+11
每次查找的起始位置和记录是关键[/quote]
这样考虑并不对啊 ,你只是考虑了连续位的项和,如果离散的话可能结果有误了,你跟1楼的程序的算法是完全一样的,你看一下这个例子,如果输入的是3 4 2 4 9,理论上输出应该是16 【就是3+4+9】,但是你的算法给出的结果是2+4+9,你看看是不是?
不过很感谢你的提示,我按你给的这种思路想想,应该会有解决办法[/quote]
那就每次遍历整个序列,直到找不到递增数为止,起始位置从断开的那个地方开始,比如3 4 2 4 9,第一次是3 4 9,第二次从2开始
我来回复