回 帖 发 新 帖 刷新版面

主题:请问这道DP题该怎么做?

题目是:给定一个数列,如何在此数列的所有单调递增子数列里找出所有项和最大的一个?
输入是若干个数,输出是满足条件的子数列的所有项之和。
例如:
input:
5 3 4 9 2 3 4 5 6 11 9
output:
31   【31=2+3+4+5+6+11】

请问对于这道题有什么好的算法没有?我想了N久没想出来,哪位大侠给个思路或贴出程序

回复列表 (共7个回复)

沙发


这个问题有必要用动态规划么.......

[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]

板凳

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 楼

基本上都大同小异,仅供参考:
   #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 楼

[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 楼

[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 楼

[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 楼

[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开始

我来回复

您尚未登录,请登录后再回复。点此登录或注册