以下思路来源于王道机试题这本书,侵删。
动态规划算法思想:与分治法类似,将待求问题分解为若干子问题,先求子问题,在利用子问题的解返回来求原问题。因为在分治法时,求出的子问题往往不是独立的,很多值被重复计算过,比如斐波那契数列计算:
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;
}