最大连续子序列和

1. 问题描述:

给定一个数字序列A1,A2,A3...An,求i,j(1,<= i <= j<=n),使得Ai + ....Aj最大,输出这个最大和

2. 思路分析:

① 这个问题假如使用暴力破解,枚举左端点和右端点(即i,j)需要O(n ^ 2)的复杂度,而计算A[i] + ....A[j]需要O(n)的复杂度,因此总的时间复杂度为O(n ^ 3),假如采用记录前缀和的方法:预处理S[i] = A[0] + A[1] + A[2] ...A[n]的值这样A[i] + .....A[j] = S[j] - S[i - 1]使得计算的时间复杂度降低为O(1)复杂度仍然维持在O(n ^ 2)这对于n在很大情况下是计算不出来的

② 除了上面的暴力破解,还可以采用的是动态规划的解法,时间复杂度为O(n),我们可以设置成dp数组的记录的是以当前元素作为末尾的连续序列的最大和,也就是dp[i]表示以A[i]为末尾的连续序列的最大和(A[i]必须作为连续序列的结尾)

比如下面的例子:-2 11 -4 13 -5 -2,下标为0,1,2,3,4,5

dp[0] = -2;

dp[1] = 11;

dp[2] = 7;(11- 4)

dp[3] = 20;(11-4 +13)

dp[4] = 15;(11-4+13-5=15)这里注意不是20,因为必须要以A[4]作为结尾

dp[5] = 13;(11-4+13-5-2)

③ 存在着两种情况,第一种是最大连续子序列只有一个元素,即以A[i]开始,以A[i]结束

第二种情况是存在多个元素的情况,即从前面的某处A[p]开始,一直到A[i]结束,最大和为dp[i - 1] + A[i],所以可以得到状态转移方程是:

dp[i] = max{A[i], dp[i - 1] + A[i]}

④ 最后遍历dp数组选出一个最大的那个就是我们需要求解的答案

3. 下面是具体的代码:

#include
#include
using namespace std;
const int maxn = 10010;
int A[maxn], dp[maxn];//dp[i]存放的是以A[i]结尾的连续序列的最大值
int main(void){
	int n;
	scanf("%d", &n);
	for(int i = 0; i < n; ++i){
		scanf("%d", &A[i]);
	}
	dp[0] = A[0];
	for(int i = 1; i < n; ++i){
		dp[i] = max(A[i], dp[i - 1] + A[i]);
	}
	int k = 0;
	for(int i = 1; i < n; ++i){
		if(dp[i] > dp[k]){
			k = i;
		}
	}
	printf("%d", dp[k]);
	return 0;
} 

 

你可能感兴趣的:(C&&C++,动态规划)