动态规划专题讲义之最大连续子序列之和
来源:互联网 发布:alias软件下载 编辑:程序博客网 时间:2024/05/19 20:39
专题三:最大连续子序列之和/* Name: 动态规划专题之最大连续子序列之和 Author: 巧若拙 Description: 最大连续子序列之和 给定K个整数的序列{ N1,N2, ..., NK },其任意连续子序列可表示为{Ni, Ni+1, ..., Nj }, 其中 1 <= i <= j <= K。最大连续子序列是所有连续子序列中元素和最大的一个, 例如给定序列{ -2, 11, -4, 13, -5, -2 },其最大连续子序列为{ 11, -4, 13 },最大和为20。 输入:测试输入包含若干测试用例,每个测试用例占2行,第1行给出正整数K( < 10000 ),第2行给出K个整数,中间用空格分隔。当K为0时,输入结束,该用例不被处理。输出:对每个测试用例,在1行里输出最大和。若所有K个元素都是负数,则定义其最大和为0。输入示例:6-2 11 -4 13 -5-210-10 1 2 3 4 -5-23 3 7 -2165 -8 3 2 5 01103-1 -5 -23-1 0 -20输出示例:2010101000*/ #include<iostream> #include<string> using namespace std; const int MAX = 10000; int MaxSubsequenceSum_1(const int A[], int n);//低效算法1 int MaxSubsequenceSum_2(const int A[], int n);//低效算法2int MaxSubsequenceSum_3(const int A[], int n);//分治算法 int MaxSubSum(const int A[], int left, int right);//分治算法子程序 int MaxSubsequenceSum_4(const int A[], int n);//使用备忘录数组的动态规划算法 int MaxSubsequenceSum_5(const int A[], int n);//使用一个变量代替备忘录数组 int main() { int A[MAX] = {0}; int n; cin >> n;while (n != 0){for (int i=0; i<n; i++)cin >> A[i];cout << MaxSubsequenceSum_1(A, n) << endl; cout << MaxSubsequenceSum_2(A, n) << endl; cout << MaxSubsequenceSum_3(A, n) << endl; cout << MaxSubsequenceSum_4(A, n) << endl; cout << MaxSubsequenceSum_5(A, n) << endl; cin >> n;} return 0; } 算法1:低效算法1:三重循环 int MaxSubsequenceSum_1(const int A[], int n)//低效算法1 { int sum, maxSum = 0; for (int i=0; i<n; i++) { for (int j=i; j<n; j++) { sum = 0; for (int k=i; k<=j; k++) //语句1 { sum += A[k]; } if (sum > maxSum) maxSum = sum; } } return maxSum; }问题1:语句1所在循环体的作用计算连续子序列A[i..j]之和,但三重循环循环看上去还是有些低效,注意变量sum的作用,想想能否去掉语句1所在循环体,提高效率?答案:问题1:详见算法2。算法2:低效算法2:二重循环int MaxSubsequenceSum_2(const int A[], int n)//低效算法2 { int sum, maxSum = 0; for (int i=0; i<n; i++) { sum = //语句1 for (int j=i; j<n; j++) { sum += //语句2 if (sum > maxSum) maxSum = //语句3 } } return maxSum; } 问题1:将语句1,语句2和语句3补充完整。答案:问题1:语句1:sum = 0; 语句2:sum += A[j]; 语句3:maxSum = sum; 算法3::分治算法 int MaxSubsequenceSum_3(const int A[], int n)//分治算法 { return MaxSubSum(A, 0, n-1); } int MaxSubSum(const int A[], int left, int right)//分治算法子程序 { int maxLeftSum, maxRightSum; int maxLeftBorderSum, maxRightBorderSum; int leftBorderSum, rightBorderSum; if (left == right) return (A[left] > 0) ? A[left] : 0; int mid = (left + right) / 2; maxLeftSum = MaxSubSum(A, left, mid); maxRightSum = MaxSubSum(A, mid+1, right); maxLeftBorderSum = leftBorderSum = 0; for (int i=mid; i>=left; i--) //语句1 { leftBorderSum += A[i]; if (leftBorderSum > maxLeftBorderSum) maxLeftBorderSum = leftBorderSum; } maxRightBorderSum = rightBorderSum = 0; for (int i=mid+1; i<=right; i++) { rightBorderSum += A[i]; if (rightBorderSum > maxRightBorderSum) maxRightBorderSum = rightBorderSum; } return max(max(maxLeftSum, maxRightSum), maxLeftBorderSum+maxRightBorderSum); } 问题1:能否把语句1改为for (int i=left; i<=mid; i++)?为什么?答案:问题1:不能。因为语句1的作用是从中间开始向左计算包含A[mid]子序列的最大和。算法4:使用备忘录数组的动态规划算法 int MaxSubsequenceSum_4(const int A[], int n)//使用备忘录数组的动态规划算法 { int S[MAX] = {A[0]};//S[i]用来存储包含A[i]的最大连续子序列之和 for (int i=1; i<n; i++) { if (S[i-1] > 0) S[i] = //语句1 else S[i] = A[i]; } int maxSum = max(0, S[0]); //语句2 for (int i=1; i<n; i++) { if (S[i] > maxSum) maxSum = S[i]; } return maxSum; } 问题1:将语句1补充完整。问题2:能否把语句1改为int maxSum = S[0];?为什么? 问题3:注意到算法4中S[i]的值只与S[i-1]有关,故无需把所有的S[i]都记录下来,可以进行降维优化,用变量sum代替S[i]实现相关功能。试着实现相关代码。答案:问题1:语句1:S[i] = S[i-1] + A[i];问题2:不能。要考虑到数组A的元素全是负数的情形。问题:3:详见算法5。 算法5:使用一个变量代替备忘录数组int MaxSubsequenceSum_5(const int A[], int n)//使用一个变量代替备忘录数组{ int sum = A[0]; int maxSum = max(0, sum); for (int i=1; i<n; i++) { if (sum > 0) { sum += A[i]; if (sum > maxSum) maxSum = sum; } else { sum = A[i]; } } return maxSum; } 拓展练习:原题只要求计算最大连续子序列之和,而没有把对应的连续子序列输出来,现在要求在算法5 MaxSubsequenceSum_5()的基础上,编写函数int MaxSubsequenceSum_6(const int A[], int n)//计算最大连续子序列之和,并输出对应的连续子序列。参考答案:int MaxSubsequenceSum_6(const int A[], int n)//使用一个变量代替备忘录数组,输出子序列 { int sum = A[0]; int maxSum = max(0, sum); int left = 0, mLeft = 0, right = 0; //mLeft和right分别存储最大连续子序列的左右边界 for (int i=1; i<n; i++)//存储各连续子序列的最大和 { if (sum > 0) //若之前的连续子序列之和大于0,则把A[i]累加上去 { sum += A[i]; if (sum > maxSum) { maxSum = sum; mLeft = left; right = i; } } else //否则重新开始 { sum = A[i]; left = i; } } if (maxSum > 0) {cout << "A[" << mLeft << ":" << right << "] : "; for (int i=mLeft; i<=right; i++) { cout << A[i] << " "; } cout << "= "; } return maxSum; }课后练习:练习1:最大m子段和问题题目描述:给定由 n个整数(可能为负整数)组成的序列a1,a2,a3,……,an,以及一个正整数 m,要求确定序列 a1,a2,a3,……,an的 m个不相交子段,使这m个子段的总和达到最大,求出最大和。 输入:每个测试用例将以两个整数m和n开始, 紧随其后的是n个整数a1,a2,a3,……,an。直到读入文件结束。输出:在一行上输出题目描述中所说的最大和。输入示例:1 3 1 2 32 6-1 4 -2 3 -2 3输出示例:68练习2:1768_最大子矩阵题目描述:已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是1 * 1)子矩阵。比如,如下4 * 4的矩阵0 -2 -7 09 2 -6 2-4 1 -4 1-1 8 0 -2的最大子矩阵是9 2-4 1-1 8这个子矩阵的大小是15。输入输入是一个N * N的矩阵。输入的第一行给出N (0 < N <= 100)。再后面的若干行中,依次(首先从左到右给出第一行的N个整数,再从左到右给出第二行的N个整数……)给出矩阵中的N2个整数,整数之间由空白字符分隔(空格或者空行)。已知矩阵中整数的范围都在[-127, 127]。输出输出最大子矩阵的大小。样例输入40 -2 -7 09 2 -6 2-4 1 -4 1-1 8 0 -2样例输出15
阅读全文
0 0
- 动态规划专题讲义之最大连续子序列之和
- 动态规划专题之最大连续子序列之和
- 最大连续子序列之和(动态规划)
- 最大连续子序列之和 动态规划 java
- 动态规划之最大连续子序列
- HDU1003 动态规划,最大子序列之和
- leetcode动态规划之连续最大子序列和
- [acm]动态规划-最大连续子序列
- 动态规划---hdu1231---最大连续子序列
- HDU1231 最大连续子序列(动态规划)
- 动态规划:最大连续子序列乘积
- [动态规划]最大连续子序列和
- HDU1231最大连续子序列(动态规划)
- 最大连续子序列和-动态规划
- 最大连续子序列和----动态规划
- 最大连续子序列----DP动态规划
- HDU_1231 最大连续子序列 【动态规划】
- 动态规划? 最大连续子序列和
- 海量数据处理
- SpringCloud(七):Ribbon自定义配置
- 析构函数和构造函数的注意事项
- Python 多线程(高级教程)
- ThingInJava-IO笔记(NIO)
- 动态规划专题讲义之最大连续子序列之和
- elasticsearch实用篇之kibana安装以及使用
- Struts2中的ActionContext和ServletActionContext的区别
- POJ--1631
- Python XML解析(高级教程)
- Struts2入门(2): 应用简单示例
- nginx 做mysql负载均衡
- zoj1109 水题(大神绕道) Language of FatMouse
- BI怎么选?重点看这10个技术指标