c++动态规划:最大连续子序列的和及其变形

以下思路来源于王道机试题这本书,侵删。
动态规划算法思想:与分治法类似,将待求问题分解为若干子问题,先求子问题,在利用子问题的解返回来求原问题。因为在分治法时,求出的子问题往往不是独立的,很多值被重复计算过,比如斐波那契数列计算:
F(n) = F(n-1)+F(n-2),F(n-1) = F(n-2) + F(n-3)。观察计算过程,F(n-2)在这个过程中就被重复计算了。
动态规划是将算过的保存下来,以后就直接用,不需要重复计算了。
以斐波那契数列为例看看动态规划

int Fibonacci(int n)
{
	const int maxn = 100;
	int dp[maxn];//用数组来存储每一步的F(n),dp[0] = F(0),dp[n] = F(n)
				 //用数组存储就是动态规划的直接体现,把算过的保存下来
	dp[0] = 0;
	dp[1] = 1;
	for(int i = 2;i<=n;i++)
	{
		dp[i] = dp[i-1] + dp[i-2];
	}
	return dp[n];
}

下面步入正题,最大连续子序列

  • 问题描述:

    给定一个序列{A1,A2,…,An},找出一个连续的子序列{Ai,…Aj},使得该子序列的和最大,并输出其和。

  • 解题思路:
    设置一个数组dp[ ],dp[i]表示以i元素为结尾的最大连续子序列的和。例如,用arr[ ]来存放子序列。dp[0] = arr[0],dp[i] = max(arr[i],dp[i-1]+arr[i])。
    附代码:

int maxsubsequence(int n,int* arr)
{
    int* dp = (int*)malloc(sizeof(int)*n);
    dp[0] = arr[0];
    int maxmum = dp[0];
    for(int i = 1;i<n;i++)
    {
        dp[i] = max(arr[i],dp[i-1]+arr[i]);
        if(maxmum < dp[i])
            maxmum = dp[i];
    }
    return maxmum;
}
  • 变体:
    在其基础上,再加一个要求,输出该最大连续子序列的首尾元素。
  • 解题思路:
    在上题基础上,用一个结构体数组代替dp数组,用来保存最大值和其首位元素。
#include<iostream>
#include<cstdio>
#include<stdlib.h>
#include<stack>

using namespace std;

typedef struct
{
    int sleft;
    int sright;
    int maxsum;
}DP;

DP maxsubsequence(int n,int* arr)
{
    DP* dp = (DP*)malloc(sizeof(DP)*n);
    dp[0].maxsum = arr[0];
    dp[0].sleft = arr[0];
    dp[0].sright = arr[0];
    int maxmum = dp[0].maxsum;
    int index;//用来存储dp数组中最大值的下标
    for(int i = 1;i<n;i++)
    {
        dp[i].maxsum = (arr[i]<(dp[i-1].maxsum+arr[i]))?dp[i-1].maxsum+arr[i]:arr[i];
        dp[i].sleft = (arr[i]<(dp[i-1].maxsum+arr[i]))?dp[i-1].sleft:arr[i];
        dp[i].sright = arr[i];
        if(maxmum < dp[i].maxsum)
        {
            maxmum = dp[i].maxsum;
            index = i;
        }
    }
    return dp[index];
}

int main()
{
    int n;
    while(scanf("%d",&n)!= EOF)
    {
        int* arr = (int*)malloc(sizeof(int)*n);
        for(int i = 0;i<n;i++)
            scanf("%d",&arr[i]);
        DP answer = maxsubsequence(n,arr);
        printf("%d %d %d\n",answer.maxsum,answer.sleft,answer.sright);
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值