最大子段和

合集下载

算法分析与设计作业参考答案

算法分析与设计作业参考答案

算法分析与设计作业参考答案《算法分析与设计》作业参考答案作业⼀⼀、名词解释:1.递归算法:直接或间接地调⽤⾃⾝的算法称为递归算法。

2.程序:程序是算法⽤某种程序设计语⾔的具体实现。

⼆、简答题:1.算法需要满⾜哪些性质?简述之。

答:算法是若⼲指令的有穷序列,满⾜性质:(1)输⼊:有零个或多个外部量作为算法的输⼊。

(2)输出:算法产⽣⾄少⼀个量作为输出。

(3)确定性:组成算法的每条指令清晰、⽆歧义。

(4)有限性:算法中每条指令的执⾏次数有限,执⾏每条指令的时间也有限。

2.简要分析分治法能解决的问题具有的特征。

答:分析分治法能解决的问题主要具有如下特征:(1)该问题的规模缩⼩到⼀定的程度就可以容易地解决;(2)该问题可以分解为若⼲个规模较⼩的相同问题,即该问题具有最优⼦结构性质;(3)利⽤该问题分解出的⼦问题的解可以合并为该问题的解;(4)该问题所分解出的各个⼦问题是相互独⽴的,即⼦问题之间不包含公共的⼦问题。

3.简要分析在递归算法中消除递归调⽤,将递归算法转化为⾮递归算法的⽅法。

答:将递归算法转化为⾮递归算法的⽅法主要有:(1)采⽤⼀个⽤户定义的栈来模拟系统的递归调⽤⼯作栈。

该⽅法通⽤性强,但本质上还是递归,只不过⼈⼯做了本来由编译器做的事情,优化效果不明显。

(2)⽤递推来实现递归函数。

(3)通过Cooper 变换、反演变换能将⼀些递归转化为尾递归,从⽽迭代求出结果。

后两种⽅法在时空复杂度上均有较⼤改善,但其适⽤范围有限。

三、算法编写及算法应⽤分析题: 1.冒泡排序算法的基本运算如下: for i ←1 to n-1 dofor j ←1 to n-i do if a[j]交换a[j]、a[j+1];分析该算法的时间复杂性。

答:排序算法的基本运算步为元素⽐较,冒泡排序算法的时间复杂性就是求⽐较次数与n 的关系。

(1)设⽐较⼀次花时间1;(2)内循环次数为:n-i 次,(i=1,…n ),花时间为:∑-=-=in j i n 1)(1(3)外循环次数为:n-1,花时间为:2.设计⼀个分治算法计算⼀棵⼆叉树的⾼度。

最大子段和-分治法

最大子段和-分治法
s 2 max
k k n 2 1
a (n 2 1 j n) ,则s1+s2为情况③的最大子段和。
j
k i
( 3 )合并:比较在划分阶段的三种情况下的最大子段和, 取三者之中的较大者为原问题的解。
a1 … … ai … amid amid+1… aj … … an
划分
(mid n 2)
leftsum
rightsum
递归处理 合并解 不能递归处理
max{leftsum, sum, rightsum} sum
a1 … … ai … amid amid+1… aj … … an
最大子段和横跨两个子序列
算法——最大子段和问题 int MaxSum(int a[ ], int left, int right) { sum=0; if (left= =right) { //如果序列长度为1,直接求解 if (a[left]>0) sum=a[left]; else sum=0; } else { center=(left+right)/2; //划分 leftsum=MaxSum(a, left, center); //对应情况①,递归求解 rightsum=MaxSum(a, center+1, right); //对应情况②,递归求解
分析算法的时间性能,对应划分得到的情况①和②, 需要分别递归求解,对应情况③,两个并列 for 循环的时 间复杂性是O(n),所以,存在如下递推式:
1 T (n) 2T (n 2) n
n 1 n 1
根据有关定理(详细见下页ppt),算法的时间复杂性为 O(nlog2n)。
T ( n) 2T ( n / 2) n 令n 2 t ,t log2 n 则T ( 2 t ) 2T ( 2 t 1 ) 2 t 2[ 2T ( 2 t 2 ) 2 t 1 ] 2 t 2 2 T (2t 2 ) 2t 2t 2 t T (1) 2 t 2 t 2 t (共有t个) (t 1) 2 t (log2 n 1) n ( n log2 n)

最大子段和问题的简单算法

最大子段和问题的简单算法

最大子段和问题的简单算法一、引言最大子段和问题(Maximum Subarray Sum Problem)是计算机科学中一个经典的问题,旨在寻找数组中的连续子数组,使得该子数组中所有元素的总和最大。

这个问题的解决方法有多种,其中包括暴力解法、分治法、动态规划等。

本篇文章将介绍一种简单且高效的解决方法——Kadane算法。

二、算法描述Kadane算法是一种基于动态规划的贪心算法,其基本思想是对于给定的数组,不断选择以当前元素结尾的最大子段和,然后将这个最大子段和更新为全局最大子段和。

算法的主要步骤如下:1. 初始化两个变量,一个是局部最大和max_ending_here,初值为数组的第一个元素;另一个是全局最大和max_global,初值为数组的第一个元素。

2. 遍历数组中的每个元素,对于当前元素,计算以当前元素结尾的最大子段和max_ending_here,然后更新全局最大和max_global。

3. 在遍历过程中,对于每个元素,都会计算出一个以该元素结尾的最大子段和,因此遍历结束后,全局最大和就是最大的子段和。

三、算法复杂度分析Kadane算法的时间复杂度为O(n),其中n是数组的长度。

因为我们需要遍历数组中的每个元素一次。

在空间复杂度方面,Kadane算法只需要常数级别的额外空间来存储两个变量,因此其空间复杂度为O(1)。

四、算法实现下面是一个用Python实现的Kadane算法:def max_subarray_sum(arr):max_ending_here = max_global = arr[0]for i in range(1, len(arr)):max_ending_here =max(arr[i], max_ending_here + arr[i])max_global =max(max_global, max_ending_here)return max_global五、结论Kadane算法是一种简单且高效的解决最大子段和问题的方法,其时间复杂度为O(n),空间复杂度为O(1)。

区间dp知识点总结

区间dp知识点总结

区间dp知识点总结区间动态规划以区间为基本单位,将区间问题分解为子区间问题,并通过子问题的优化解来求解原问题的最优解。

在区间动态规划中,我们通常会先对区间进行预处理,然后进行状态转移和最优解的计算,最终得出整个区间的最优解。

本文将介绍区间动态规划的基本概念、相关术语、常用技巧和应用场景,并以具体的例题进行解析,希望能够帮助读者更好地理解并掌握区间动态规划的相关知识。

一、基本概念1. 区间在区间动态规划中,区间通常是指一段连续的序列,可以是数组、字符串或其他数据结构。

如有一个长度为n的数组,通常我们可以将数组的某个子区间[i, j]表示为数组的一段连续元素,其中i和j分别为区间的左右边界。

2. 状态在区间动态规划中,状态通常用来表示问题的解空间,它是问题的一个关键要素。

状态的选择不同,可能会导致不同的算法解法。

3. 状态转移方程区间动态规划的核心是状态转移方程,它描述了问题的状态如何转移,以及如何通过子问题的最优解来求解原问题的最优解。

状态转移方程通常包括两个方面:状态之间的转移关系和状态的初始值。

4. 最优解区间动态规划通常是要求解区间范围内的最优解问题。

最优解可能是指区间的最大值、最小值、最长子序列等。

二、相关术语1. 最长上升子序列(Longest Increasing Subsequence,简称LIS)最长上升子序列是指一个序列中各个元素都严格递增的子序列,且该子序列的长度最大。

在区间动态规划中,求解最长上升子序列的长度是一个常见的问题。

2. 最大子段和(Maximum Subarray Sum)最大子段和是指一个序列中连续元素的和中最大的值。

在区间动态规划中,求解最大子段和也是一个常见的问题。

3. 背包问题背包问题是一类经典的组合优化问题,它包括 0-1 背包问题、多重背包问题、分组背包问题等。

在区间动态规划中,背包问题的求解也是一个重要的应用场景。

4. 字符串处理字符串处理是区间动态规划中一个重要的应用场景,常见的问题包括编辑距离、最长公共子序列、最长回文子串等。

最大子段和例题

最大子段和例题

选择题在求解最大子段和的问题时,以下哪种算法的时间复杂度最优?A. 暴力枚举法B. 分治法C. 动态规划法(正确答案)D. 贪心算法(特定情况下)给定数组[-2, 1, -3, 4, -1, 2, 1, -5, 4],其最大子段和是:A. 6B. 7C. 8(正确答案)D. 9最大子段和问题中,若数组所有元素均为负数,则最大子段和为:A. 数组中的最大值B. 数组中的最小值(但仍是负数)C. 0(正确答案,即空子段)D. 不存在使用动态规划求解最大子段和时,状态转移方程通常表示为:A. dp[i] = max(dp[i-1]+a[i], a[i])(正确答案)B. dp[i] = min(dp[i-1]+a[i], a[i])C. dp[i] = dp[i-1] * a[i]D. dp[i] = dp[i-1] + a[i]下列哪个数组的最大子段和等于其所有元素之和?A. [1, -2, 3, -4]B. [-1, -2, -3, -4]C. [1, 2, 3, 4](正确答案)D. [0, -1, -1, 0]在求解最大子段和的分治算法中,如果将问题分为两个子问题,每个子问题的规模大约是原问题的一半,那么合并两个子问题的解的时间复杂度是:A. O(n)B. O(log n)C. O(1)(正确答案)D. O(n2)给定数组[a, b, c, d],若a+b<0且c+d>0,则关于其最大子段和的说法正确的是:A. 最大子段和一定包含a和bB. 最大子段和一定不包含c和dC. 最大子段和可能只包含c和d(正确答案)D. 最大子段和一定是整个数组的和对于一个全为正数的数组,其最大子段和:A. 一定小于数组中的最大值B. 一定等于数组中的最大值C. 一定大于数组中的最大值D. 一定等于数组所有元素之和(正确答案)在动态规划求解最大子段和的过程中,dp[i]表示:A. 以第i个元素结尾的最大子段和(正确答案)B. 以第i个元素开头的最大子段和C. 从第1个元素到第i个元素的最大子段和D. 从第i个元素到最后一个元素的最大子段和。

计算机算法设计和分析习题及答案解析

计算机算法设计和分析习题及答案解析

计算机算法设计与分析习题及答案一.选择题1、二分搜索算法是利用 A 实现的算法;A、分治策略B、动态规划法C、贪心法D、回溯法2、下列不是动态规划算法基本步骤的是 A ;A、找出最优解的性质B、构造最优解C、算出最优解D、定义最优解3、最大效益优先是A 的一搜索方式;A、分支界限法B、动态规划法C、贪心法D、回溯法4. 回溯法解旅行售货员问题时的解空间树是 A ;A、子集树B、排列树C、深度优先生成树D、广度优先生成树5.下列算法中通常以自底向上的方式求解最优解的是B ;A、备忘录法B、动态规划法C、贪心法D、回溯法6、衡量一个算法好坏的标准是 C ;A 运行速度快B 占用空间少C 时间复杂度低D 代码短7、以下不可以使用分治法求解的是 D ;A 棋盘覆盖问题B 选择问题C 归并排序D 0/1背包问题8. 实现循环赛日程表利用的算法是A ;A、分治策略B、动态规划法C、贪心法D、回溯法9.下面不是分支界限法搜索方式的是D ;A、广度优先B、最小耗费优先C、最大效益优先D、深度优先10.下列算法中通常以深度优先方式系统搜索问题解的是D ;A、备忘录法B、动态规划法C、贪心法D、回溯法11.备忘录方法是那种算法的变形; BA、分治法B、动态规划法C、贪心法D、回溯法12.哈夫曼编码的贪心算法所需的计算时间为B ;A、On2nB、OnlognC、O2nD、On13.分支限界法解最大团问题时,活结点表的组织形式是B ;A、最小堆B、最大堆C、栈D、数组14.最长公共子序列算法利用的算法是B;A、分支界限法B、动态规划法C、贪心法D、回溯法15.实现棋盘覆盖算法利用的算法是A ;A、分治法B、动态规划法C、贪心法D、回溯法16.下面是贪心算法的基本要素的是C ;A、重叠子问题B、构造最优解C、贪心选择性质D、定义最优解17.回溯法的效率不依赖于下列哪些因素 DA.满足显约束的值的个数B. 计算约束函数的时间C.计算限界函数的时间D. 确定解空间的时间18.下面哪种函数是回溯法中为避免无效搜索采取的策略BA.递归函数 B.剪枝函数 C;随机数函数 D.搜索函数19. D是贪心算法与动态规划算法的共同点;A、重叠子问题B、构造最优解C、贪心选择性质D、最优子结构性质20. 矩阵连乘问题的算法可由 B 设计实现;A、分支界限算法B、动态规划算法C、贪心算法D、回溯算法21. 分支限界法解旅行售货员问题时,活结点表的组织形式是 A ;A、最小堆B、最大堆C、栈D、数组22、Strassen矩阵乘法是利用A 实现的算法;A、分治策略B、动态规划法C、贪心法D、回溯法23、使用分治法求解不需要满足的条件是 A ;A 子问题必须是一样的B 子问题不能够重复C 子问题的解可以合并D 原问题和子问题使用相同的方法解24、下面问题 B 不能使用贪心法解决;A 单源最短路径问题B N皇后问题C 最小生成树问题D 背包问题25、下列算法中不能解决0/1背包问题的是 AA 贪心法B 动态规划C 回溯法D 分支限界法26、回溯法搜索状态空间树是按照 C 的顺序;A 中序遍历B 广度优先遍历C 深度优先遍历D 层次优先遍历27.实现合并排序利用的算法是A ;A、分治策略B、动态规划法C、贪心法D、回溯法28.下列是动态规划算法基本要素的是D ;A、定义最优解B、构造最优解C、算出最优解D、子问题重叠性质29.下列算法中通常以自底向下的方式求解最优解的是 B ;A、分治法B、动态规划法C、贪心法D、回溯法30.采用广度优先策略搜索的算法是A ;A、分支界限法B、动态规划法C、贪心法D、回溯法31、合并排序算法是利用 A 实现的算法;A、分治策略B、动态规划法C、贪心法D、回溯法32、背包问题的贪心算法所需的计算时间为 BA、On2nB、OnlognC、O2nD、On33.实现大整数的乘法是利用的算法C ;A、贪心法B、动态规划法C、分治策略D、回溯法34.0-1背包问题的回溯算法所需的计算时间为AA、On2nB、OnlognC、O2nD、On35.采用最大效益优先搜索方式的算法是A;A、分支界限法B、动态规划法C、贪心法D、回溯法36.贪心算法与动态规划算法的主要区别是B;A、最优子结构B、贪心选择性质C、构造最优解D、定义最优解37. 实现最大子段和利用的算法是B ;A、分治策略B、动态规划法C、贪心法D、回溯法38.优先队列式分支限界法选取扩展结点的原则是 C ;A、先进先出B、后进先出C、结点的优先级D、随机39.背包问题的贪心算法所需的计算时间为 B ;A、On2nB、OnlognC、O2nD、On40、广度优先是A 的一搜索方式;A、分支界限法B、动态规划法C、贪心法D、回溯法41. 一个问题可用动态规划算法或贪心算法求解的关键特征是问题的 B ;A、重叠子问题B、最优子结构性质C、贪心选择性质D、定义最优解42.采用贪心算法的最优装载问题的主要计算量在于将集装箱依其重量从小到大排序,故算法的时间复杂度为 B ;A 、On2nB 、OnlognC 、O2nD 、On43. 以深度优先方式系统搜索问题解的算法称为 D ;A 、分支界限算法B 、概率算法C 、贪心算法D 、回溯算法44. 实现最长公共子序列利用的算法是B ;A 、分治策略B 、动态规划法C 、贪心法D 、回溯法45. Hanoi 塔问题如下图所示;现要求将塔座A 上的的所有圆盘移到塔座B 上,并仍按同样顺序叠置;移动圆盘时遵守Hanoi 塔问题的移动规则;由此设计出解Hanoi 塔问题的递归算法正确的为:B46. 动态规划算法的基本要素为 CA. 最优子结构性质与贪心选择性质 B .重叠子问题性质与贪心选择性质C .最优子结构性质与重叠子问题性质 D. 预排序与递归调用 47. 能采用贪心算法求最优解的问题,一般具有的重要性质为: AA. 最优子结构性质与贪心选择性质 B .重叠子问题性质与贪心选择性质C .最优子结构性质与重叠子问题性质 D. 预排序与递归调用48. 回溯法在问题的解空间树中,按 D 策略,从根结点出发搜索解空间树;A.广度优先B. 活结点优先C.扩展结点优先D. 深度优先49. 分支限界法在问题的解空间树中,按 A 策略,从根结点出发搜索解空间树;A.广度优先B. 活结点优先C.扩展结点优先D. 深度优先50. 程序块 A 是回溯法中遍历排列树的算法框架程序;A.B. C. D. 51. 常见的两种分支限界法为DA. 广度优先分支限界法与深度优先分支限界法;B. 队列式FIFO 分支限界法与堆栈式分支限界法;C. 排列树法与子集树法;D. 队列式FIFO 分支限界法与优先队列式分支限界法;1.算法的复杂性有 时间 复杂性和 空间 ;2、程序是 算法用某种程序设计语言的具体实现;3、算法的“确定性”指的是组成算法的每条 指令 是清晰的,无歧义的;4. 矩阵连乘问题的算法可由 动态规划 设计实现;5、算法是指解决问题的 一种方法 或 一个过程 ;6、从分治法的一般设计模式可以看出,用它设计出的程序一般是 递归算法 ;7、问题的 最优子结构性质 是该问题可用动态规划算法或贪心算法求解的关键特征;8、以深度优先方式系统搜索问题解的算法称为 回溯法 ;9、计算一个算法时间复杂度通常可以计算 循环次数 、 基本操作的频率 或计算步; Hanoi 塔A. void hanoiint n, int A, int C, int B{ if n > 0{ hanoin-1,A,C, B;moven,a,b; hanoin-1, C, B, A; }} B. void hanoiint n, int A, int B, int C { if n > 0 { hanoin-1, A, C, B; moven,a,b; hanoin-1, C, B, A; } }C. void hanoiint n, int C, int B, int A { if n > 0 { hanoin-1, A, C, B; moven,a,b; hanoin-1, C, B, A; } }D. void hanoiint n, int C, int A, int B { if n > 0 { hanoin-1, A, C, B; moven,a,b; hanoin-1, C, B, A; } } void backtrack int t{ if t>n outputx; else for int i=t;i<=n;i++ { swapxt, xi; if legalt backtrackt+1; swapxt, xi; } } void backtrack int t { if t>n outputx;elsefor int i=0;i<=1;i++ { xt=i; if legalt backtrackt+1; } }void backtrack int t { if t>n outputx; else for int i=0;i<=1;i++ { xt=i; if legalt backtrackt-1; } }voidbacktrack int t{ if t>n outputx; else for int i=t;i<=n;i++ { swapxt, xi; if legalt backtrackt+1;}}10、解决0/1背包问题可以使用动态规划、回溯法和分支限界法,其中不需要排序的是动态规划 ,需要排序的是回溯法 ,分支限界法 ;11、使用回溯法进行状态空间树裁剪分支时一般有两个标准:约束条件和目标函数的界,N皇后问题和0/1背包问题正好是两种不同的类型,其中同时使用约束条件和目标函数的界进行裁剪的是 0/1背包问题 ,只使用约束条件进行裁剪的是 N皇后问题 ;12、贪心选择性质是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法的主要区别;13、矩阵连乘问题的算法可由动态规划设计实现;14.贪心算法的基本要素是贪心选择性质和最优子结构性质 ;15. 动态规划算法的基本思想是将待求解问题分解成若干子问题 ,先求解子问题 ,然后从这些子问题的解得到原问题的解;16.算法是由若干条指令组成的有穷序列,且要满足输入、输出、确定性和有限性四条性质;17、大整数乘积算法是用分治法来设计的;18、以广度优先或以最小耗费方式搜索问题解的算法称为分支限界法 ;19、贪心选择性质是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法的主要区别;20.快速排序算法是基于分治策略的一种排序算法;21.动态规划算法的两个基本要素是. 最优子结构性质和重叠子问题性质 ;22.回溯法是一种既带有系统性又带有跳跃性的搜索算法;23.分支限界法主要有队列式FIFO 分支限界法和优先队列式分支限界法;24.分支限界法是一种既带有系统性又带有跳跃性的搜索算法;25.回溯法搜索解空间树时,常用的两种剪枝函数为约束函数和限界函数 ;26.任何可用计算机求解的问题所需的时间都与其规模有关;27.快速排序算法的性能取决于划分的对称性 ;28.所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到 ;29.所谓最优子结构性质是指问题的最优解包含了其子问题的最优解 ;30.回溯法是指具有限界函数的深度优先生成法 ;31.用回溯法解题的一个显着特征是在搜索过程中动态产生问题的解空间;在任何时刻,算法只保存从根结点到当前扩展结点的路径;如果解空间树中从根结点到叶结点的最长路径的长度为hn,则回溯法所需的计算空间通常为 Ohn ;32.回溯法的算法框架按照问题的解空间一般分为子集树算法框架与排列树算法框架;33.用回溯法解0/1背包问题时,该问题的解空间结构为子集树结构;34.用回溯法解批处理作业调度问题时,该问题的解空间结构为排列树结构;35.旅行售货员问题的解空间树是排列树 ;三、算法填空1.背包问题的贪心算法void Knapsackint n,float M,float v,float w,float x{//重量为w1..n,价值为v1..n的 n个物品,装入容量为M的背包//用贪心算法求最优解向量x1..nint i; Sortn,v,w;for i=1;i<=n;i++ xi=0;float c=M;for i=1;i<=n;i++{if wi>c break;xi=1;c-=wi;}if i<=n xi=c/wi;}2.最大子段和: 动态规划算法int MaxSumint n, int a{int sum=0, b=0; //sum存储当前最大的bj, b存储bjfor int j=1; j<=n; j++{ if b>0 b+= aj ;else b=ai; ; //一旦某个区段和为负,则从下一个位置累和 ifb>sum sum=b;}return sum;}3.贪心算法求活动安排问题template<class Type>void GreedySelector int n, Type s, Type f, bool A{A1=true;int j=1;for int i=2;i<=n;i++if si>=fj{ Ai=true;j=i;}else Ai=false;}4.快速排序template<class Type>void QuickSort Type a, int p, int r{if p<r{int q=Partitiona,p,r;QuickSort a,p,q-1; //对左半段排序QuickSort a,q+1,r; //对右半段排序}}5. 回溯法解迷宫问题迷宫用二维数组存储,用'H'表示墙,'O'表示通道int x1,y1,success=0; //出口点void MazePathint x,int y{//递归求解:求迷宫maze从入口x,y到出口x1,y1的一条路径mazexy=''; //路径置为if x==x1&&y==y1 success=1; //到出口则成功else{if mazexy+1=='O' MazePathx,++y;//东邻方格是通路,向东尝试if success&&mazex+1y=='O' MazePath++x,y;//不成功且南邻方格是通路,向南尝试if success&&mazexy-1=='O' MazePathx,--y;//不成功且西邻方格是通路,向西尝试if success&&mazex-1y=='O' MazePath--x,y;//不成功且北邻方格是通路,向北尝试}if success mazexy=''; //死胡同置为}四、算法设计题1. 给定已按升序排好序的n个元素a0:n-1,现要在这n个元素中找出一特定元素x,返回其在数组中的位置,如果未找到返回-1;写出二分搜索的算法,并分析其时间复杂度;template<class Type>int BinarySearchType a, const Type& x, int n{//在a0:n中搜索x,找到x时返回其在数组中的位置,否则返回-1Int left=0; int right=n-1;While left<=right{int middle=left+right/2;if x==amiddle return middle;if x>amiddle left=middle+1;else right=middle-1;}Return -1;}时间复杂性为Ologn2. 利用分治算法写出合并排序的算法,并分析其时间复杂度void MergeSortType a, int left, int right{if left<right {//至少有2个元素int i=left+right/2; //取中点mergeSorta, left, i;mergeSorta, i+1, right;mergea, b, left, i, right; //合并到数组bcopya, b, left, right; //复制回数组a}}算法在最坏情况下的时间复杂度为Onlogn;3.N皇后回溯法bool Queen::Placeint k{ //检查xk位置是否合法for int j=1;j<k;j++if absk-j==absxj-xk||xj==xk return false;return true;}void Queen::Backtrackint t{if t>n sum++;else for int i=1;i<=n;i++{xt=i;if 约束函数 Backtrackt+1;}}4.最大团问题void Clique::Backtrackint i // 计算最大团{ if i > n { // 到达叶结点for int j = 1; j <= n; j++ bestxj = xj;bestn = cn; return;}// 检查顶点 i 与当前团的连接int OK = 1;for int j = 1; j < i; j++if xj && aij == 0 // i与j不相连{OK = 0; break;}if OK { // 进入左子树xi = 1; cn++;Backtracki+1;xi = 0; cn--; }if cn+n-i>bestn { // 进入右子树xi = 0;Backtracki+1; }}5. 顺序表存储表示如下:typedef struct{RedType rMAXSIZE+1; //顺序表int length; //顺序表长度}SqList;编写对顺序表L进行快速排序的算法;int PartitionSqList &L,int low,int high //算法10.6b{//交换顺序表L中子表L.rlow..high的记录,枢轴记录到位,并返回其所在位置, //此时在它之前后的记录均不大小于它.int pivotkey;L.r0=L.rlow; //用子表的第一个记录作枢轴记录pivotkey=L.rlow.key; //枢轴记录关键字while low<high //从表的两端交替地向中间扫描{while low<high&&L.rhigh.key>=pivotkey --high;L.rlow=L.rhigh; //将比枢轴记录小的记录移到低端while low<high&&L.rlow.key<=pivotkey ++low;L.rhigh=L.rlow; //将比枢轴记录大的记录移到高端}L.rlow=L.r0; //枢轴记录到位return low; //返回枢轴位置}void QSortSqList &L,int low,int high{//对顺序表L中的子序列L.rlow..high作快速排序int pivotloc;if low<high //长度>1{pivotloc=PartitionL,low,high; //将L.rlow..high一分为二QSortL,low,pivotloc-1; //对低子表递归排序,pivotloc是枢轴位置 QSortL,pivotloc+1,high; //对高子表递归排序}}void QuickSortSqList &L{//对顺序表L作快速排序QSortL,1,L.length; }。

动态规划——最大子段和

动态规划——最⼤⼦段和⼀、最⼤⼦段和问题给定N个数A1, A2, ... An,从中选出k(k不固定)个连续的数字 Ai, Ai+1, ... Ai+k-1,使得∑i+k−1iAt 达到最⼤,求该最⼤值。

分析求最⼤⼦段和可以⽤多种算法来解决.(1)直接枚举max = 0;for i in [1...n]for j in [i....n]sum = 0;for k in [i...j]sum += A[k]if(sum > max)max = sum//时间复杂度为O(n^3)(2)求 sum[i...j]时,直接利⽤ sum[i...j] = sum[i...j-1] + A[j]来优化max = 0;for i in [1...n]sum = 0for j in [i....n]sum += A[j]if(sum > max)max = sum//时间复杂度为O(n^2)(3)分治法将A1...An⽤⼆分法分为左右两边,则A1...An中的最⼤连续⼦段和可能为三种情况:【1】是A1...An/2中的最⼤连续⼦段和【2】是An/2+1....An中的最⼤连续⼦段和【3】横跨左右两边int MaxSum(int* a, int beg, int end){if (beg == end){return a[beg] > 0? a[beg] :0;}int mid = (beg + end) / 2;int max_left = MaxSum(a, beg, mid);int max_right = MaxSum(a, mid + 1 ,end);int s1 = 0, s2 = 0, m_left = 0, m_right = 0;for(int i = mid; i <= beg; i --){s1 += a[i];if(s1 > m_left)m_left = s1;}for(int i = mid+1; i <= end; i ++){s2 += a[i];if(s2 > m_right)m_right = s2;}int max_sum = max_left;if(max_right > max_sum)max_sum = max_right;if(m_right + m_left > max_sum)max_sum = m_left + m_right;return max_sum;}//时间复杂度为 O(nlogn)(4)动态规划算法⽤动归数组 dp[i]表⽰以Ai结尾的若⼲个连续⼦段的和的最⼤值,则有递推公式:dp[i] = max{dp[i-1] + A[i], A[i]}int max = 0;for(int i = 1; i <= n; i ++){if(dp[i-1] > 0){dp[i] = dp[i-1] + A[i];}else{dp[i] = A[i];}if(dp[i]> max){max = dp[i];}}//时间复杂度为O(n)⼆、最⼤⼦矩阵和问题给定MxN的矩阵,其⼦矩阵R{x1, y1, x2, y2} (x1, y1) 为矩阵左上⾓的坐标,(x2, y2)为矩阵右下⾓的坐标,S(x1,y1,x2,y2)表⽰⼦矩阵R中的数字的和,求所有⼦矩阵的和的最⼤值。

算法实验3-最大子段和问题实验报告

昆明理工大学信息工程与自动化学院学生实验报告( 2011 — 2012 学年 第 1 学期 )课程名称:算法设计与分析 开课实验室:信自楼机房444 2012 年12月 14日一、上机目的及内容1.上机内容给定有n 个整数(可能有负整数)组成的序列(a 1,a 2,…,a n ),求改序列形如∑=jk ka1的子段和的最大值,当所有整数均为负整数时,其最大子段和为0。

2.上机目的(1)复习数据结构课程的相关知识,实现课程间的平滑过渡; (2)掌握并应用算法的数学分析和后验分析方法;(3)理解这样一个观点:不同的算法能够解决相同的问题,这些算法的解题思路不同,复杂程度不同,解题效率也不同。

二、实验原理及基本技术路线图(方框原理图或程序流程图)(1)分别用蛮力法、分治法和动态规划法设计最大子段和问题的算法; 蛮力法设计原理:利用3个for 的嵌套(实现从第1个数开始计算子段长度为1,2,3…n 的子段和,同理计算出第2个数开始的长度为1,2,3…n-1的子段和,依次类推到第n 个数开始计算的长为1的子段和)和一个if (用来比较大小),将其所有子段的和计算出来并将最大子段和赋值给summax1。

用了3个for 嵌套所以时间复杂性为○(n 3);分治法设计原理:1)、划分:按照平衡子问题的原则,将序列(1a ,2a ,…,na )划分成长度相同的两个字序列(1a ,…,⎣⎦2/n a )和(⎣⎦12/+n a ,…,na )。

2)、求解子问题:对于划分阶段的情况分别的两段可用递归求解,如果最大子段和在两端之间需要分别计算s1=⎣⎦⎣⎦)2/1(max2/n i an ik k≤≤∑=,s2=⎣⎦⎣⎦)2/(max12/n j n ajn k k≤≤∑+=,则s1+s2为最大子段和。

若然只在左边或右边,那就好办了,前者视s1为summax2,后者视s2 o summax2。

3)、合并:比较在划分阶段的3种情况下的最大子段和,取三者之中的较大者为原问题的解。

谈最大子段和问题的三种解题策略

最大子段和问题的不同策略分析与实现最大子段和问题描述:给定由N 个整数(可能为负整数)组成的序列a 1,a 2,…,a n ,求该序列形如∑=ji k k a 的子段和的最大值。

当所有整数均为负整数时定义其最大子段和为0。

例如当(a 1,a 2,…,a 6)=(-2,11,-4,13,-5,-2)时最大子段和为20,即a 2,a 3,a 4序列为最大子段。

下面我们来探讨一下解决这个问题的三种不同策略。

一、枚举策略这种策略是我们最容易想到的,依照最大子段和的定义,不难理解所求最大子段和为max{0,max ∑=ji k k a (其中1≤i ≤j ≤n)},所以我们只需枚举所有的i 和j 即可求出序列的最大的子段和。

主要代码如下,其中a[i]表示a i 。

procedure maxsum(V AR max :longint);vari,j :integer;thissum :longint;beginmax :=0;for i :=1 to n dobeginthissum :=0;for j :=i to n dobeginthissum :=thissum+a[j];if max<thissum then max :=thissum;end;end;end;此算法的时间复杂度为O(n 2)。

二、分治策略针对最大子段和这个具体问题本身结构,我们还能够从算法设计策略上对上述算法实行改进。

从问题解的结构能够看出,它适合于分治算法求解。

如果将所给的序列a 1,a 2,…,a n 分为长度相等的两段序列a 1,a 2,…,a (n div 2) 和a (n div 2+1),a (n div 2+2),…,a n ,分别求出这两段的最大子段和,则a 1,a 2,…,a n 的最大子段和有三种可能:1.a 1,a 2,…,a n 的最大子段在前半段,即序列a 1,a 2,…,a n 的最大子段和与a 1,a 2,…,a (n div 2) 序列的最大子段和相等。

分治法求最大子段和问题

分治法求最大子段和问题共有四种方法:算法一;算法三;算法三、Divide and Conquer算法四源代码、On-line Algorithm算法一源代码:/*Given (possibly negative) integers Al, A2, •: AN, find the maximum value.找最大子段和*7# include<stdio.h>#include <time.h>#include <windows.h>int MaxSubsequenceSum(int A[],int N);main(){int LN/A,MaxSumjudge;LARGEJNTEGER begin z end,frequency; 〃代表64位有符号整数,记录程序运行时间QueryPerformanceFrequency(&frequency);//oJ'以获得当前的处理器的频率printff输入整数的个数:”);scanf(”%cT&N);A=(int *)malloc(N*sizeof(int)); //用数组给数据动态分配空间printf("自行输入数据请按1,随机产生数据请按2\n"); scanf(,,%d,,,&judge);if(judge==l){ 〃自行输入数据printff■输入%d 个整数:“,N);for(i=0;i<N;i++)scanf(”%d”,&A[i]);}else{printf(“随机产生的%d个整数为:\n“,N); 〃用随机种子随机产生N个0-999的整数srand(time(0));for (i=0;i<N;i++){if(rand()%2==0) 〃利用随机数奇偶性的等概率使得正负数约各占一半A[i]=ra nd()%1000;elseA[i]=(-l)*rand()%1000; printf("%d\t",A[i]);}}QueryPerformanceCounter(&begin); 〃记录算法1 开始时间MaxSum=MaxSubsequenceSum(A,N);QueryPerformanceCounter(&end); 〃记录算法1 终止时间printf(H\n 最大子段和为:%d\n H,MaxSum);printff 算法 1 运行时间为:%fsecon ds\n,,/(double)(end.QuadPart-begin.QuadPart)/frequency.QuadPart);// 终止时间■开始时间 =算法1运行时间systemCpause");} int MaxSubsequenceSum(int A[],int N){int ThisSum,MaxSum=O,i,j,k; 〃对最大值初始化for(i=0;i<N;i++) 〃从A[i]开始for(戸;j<N;j++){ 〃以A[j]结束ThisSum=0;for(k=i;k<=j;k++)ThisSum+=A[k]; 〃从A[i倒A[j]求和if(ThisSum>MaxSum)MaxSum=ThisSum; 〃更新最人值}return MaxSum;}算法2源代码:/*Given (possibly negative) integers Al, A2, •: AN, find the maximum value.找最大子段和*7# include<stdio.h>#include <time.h>#include <windows.h>int MaxSubsequenceSum(int A[],int N);main(){int i z N,*A,MaxSumjudge;LARGEJNTEGER begin z end,frequency; 〃代表64位有符号整数,记录程序运行时间QueryPerformanceFrequency(&frequency);//oJ'以获得当前的处理器的频率printff*输入整数的个数:");scanf(”%cT&N);A=(int *)malloc(N*sizeof(int)); //用数组给数据动态分配空间printf("自行输入数据请按1,随机产生数据请按2\n"); scanf(,,%d,,,&judge);if(judge==l){ 〃自行输入数据printff■输入%d 个整数:“,N);for(i=0;i<N;i++)scanf( ”%d”,&A[i]);}else{printf「随机产生的%:1个整数为:\『:N); 〃用随机种子随机产生N个0-999的整数srand(time(0));for (i=0;i<N;i++){if(rand()%2==0) 〃利用随机数奇偶性的等概率使得正负数约各占一半A[i]=ra nd()%1000;elseA[i]=(-l)*rand()%1000;printf(”%d\t“,A[i]);}}QueryPerformanceCounter(&begin); 〃记录算法2 开始时间MaxSum=MaxSubsequenceSum(A,N);QueryPerformanceCounter(&end); 〃记录算法2 终止时间printf("\n 最大子段和为:%d\n"z MaxSum);printff1算法2 运行时间为:%f seconds\n M,(double)(end.QuadPart-begin.QuadPart)/frequency.QuadPart); 〃终止时间■开始时间二算法2运行时间systemCpause");}int MaxSubsequenceSum(int A[],int N){int ThisSum^axSum^JJ; 〃对最人值初始化for(i=0;i<N;i++){ 〃从A[i]开始ThisSum=0;for(戸;j<N;j++){ 〃以A[j]结束ThisSum+=A[j]; 〃从A[i倒A[j]求和if(ThisSum>MaxSum)MaxSum=ThisSum; 〃更新最人值}}return MaxSum;}算法三源代码:分治法/*Given (possibly negative) integers Al, A2Z•: AN, find the maximum value.找最大子段和*7 # include<stdio.h>#include <time.h>#include <windows.h>int Divide_Conquer(int a[]Jnt leftjnt right);main()int i^/A,MaxSumjudge;LARGEJNTEGER begin,end,frequency; 〃代表64位有符号整数,记录程序运行时河QueryPerformanceFrequency(&frequency);//oJ'以获得当前的处理器的频率printff*输入整数的个数:");scanfC%cT&N);A=(int *)malloc(N*sizeof(int)); //用数组给数据动态分配空间printf("自行输入数据请按1,随机产生数据请按2\n");scanf(,,%d,,/&judge);if(judge==l){ 〃自行输入数据printf(“输A%d 个整数:“,N);for(i=0;i<N;i++)scanf(”%d”,&A[i]);}else{printf(”随机产生的%:1个整数为:\n“,N);〃用随机种子随机产生N个0-999的整数srand(time(0));for (i=0;i<N;i++){if(rand()%2==0) 〃利用随机数奇偶性的等概率使得正负数约各占一半A[i]=ra nd()%1000;elseA[i]=(-l)*rand()%1000;printf(”%d\t",A[i]);}}QueryPerformanceCounter(&begin); 〃记录算法3 开始时河MaxSum=Divide_Co nquer(AQN);QueryPerformanceCounter(&end); 〃记录算法3 终止时间printf("\n 最大子段和为:%d\n"z MaxSum);printff 算法3 运行时间为:%f secon ds\n,,/(double)(end.QuadPart-begin.QuadPart)/frequency.QuadPart); 〃终11:时间-开始时间二算法3运行时间systemCpause");}int Divide_Conquer(int a[]Jnt left,int right)//分治算法{int sum=0Jeftsum=0/rightsum=0,ce nterj;if(left==right){if(a[left]>0)sum=a[left];elsesum=0;else{center=(left+right)/2; 〃将数据一分为2leftsum=Divide_Conquer(a z left,center); 〃递归求左边区间的数据的最大子段rightsum=Divide_Conquer(a,center+l,right); //递归求右边区间的数据的最大子段int sl=O,lefts=O;for(i=center;i>=left;i-){ //求左边区间的数据的最大子段lefts+=a[i]; if(lefts>=sl) sl=lefts;}int s2=0/rights=0;for(i=center+l;i<=right;i++){//求右边区间的数据的最大子段rights+=a[i];if(rights>=s2) s2=rights;}sum=sl+s2;if(sum<leftsum) 〃最丿€ 值更新sum=leftsum;讦(sum<rightsum)sum=rightsum;}return sum;}算法四源代码:On-line Algorithm/*Given (possibly negative) integers Al, A2, •: AN, find the maximum value.找最大子段和*7# include<stdio.h>#include <time.h>#include <windows.h>int MaxSubsequenceSum(int A[],int N);main(){int MaxSumjudge;LARGEJNTEGER begin z end,frequency; 〃代表64位有符号整数,记录程序运行时间QueryPerformanceFrequency(&frequency);//oJ'以获得当前的处理器的频率printff输入整数的个数:");scanf(”%cT&N);A=(int *)malloc(N*sizeof(int)); //用数组给数据动态分配空间printf("自行输入数据请按1,随机产生数据请按2\n"); scanf(,,%d,,,&judge);if(judge==l){ //自行输入数据printf「输入%4个整数:鳥N);for(i=0;i<N;i++)scanf( ”%d”,&A[i]);}else{printf(”随机产生的%:1个整数为:\n“,N);〃用随机种子随机产生N个0-999的整数srand(time(0));for (i=0;i<N;i++){if(rand()%2==0) 〃利用随机数奇偶性的等概率使得正负数约各占一半A[i]=ra nd()%1000;elseA[i]=(-l)*rand()%1000;printf(“%d\t“,A[i]);}}QueryPerformanceCounter(&begin); 〃记录算法4 开始时间MaxSum=MaxSubsequenceSum(A,N);QueryPerformanceCounter(&end); 〃记录算法4 终止时间printf("\n 最大子段和为:%d\n",MaxSum);printff 算法4 运行时间为:%f seconds\n,,/(double)(end.QuadPart-begin.QuadPart)/frequency.QuadPart);// 终止时间■开始时间二算法1运行时间systemCpause");}int MaxSubsequenceSum(int A[],int N){int ThisSum^axSumj;ThisSum=0;MaxSum=0; 〃对最人值初始化for(j=0;j<N;j++){ 〃从A[j]开始ThisSum += A[j]; 〃从A[i倒A[j]求和if(ThisSum>MaxSum)MaxSum=ThisSum; 〃更新最人值else if(ThisSum<0)ThisSum=0; 〃若和为负,则为0,舍去return MaxSum;。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

最大子串和
实验题目
给定n个整数组成序列,求该序列的子段和的最大值,当所有整数均为负数时,其最大子段和为0.
实验目的
(1)深刻掌握动态规划法的设计思想并能熟练运用;
(2)理解这样一个观点:同样的问题可以用不同的方法解决,一个好的算法是反复修正的结果。

实验要求
()分别用蛮力法,分治法和动态规划法设计最大子段和问题的算法
()比较不同的算法的时间性能;
()给出测试数据,写出程序文档。

源代码
//蛮力法
#include <iostream>
using namespace std;
void main()
{
int n,j,i,sum,max=0;
int a[100],b[100];
cout<<"输入序列元素个数:";
cin>>n;
cout<<"输入序列元素:"<<endl;
for(i=1;i<=n;i++)
cin>>a[i];
for(j=1;j<=n;j++)
{
b[j]=0;
sum=0;
for(i=j;i<=n;i++)
{
sum=sum+a[i];
if(sum>b[j])
{
b[j]=sum;
}
continue;
}
}
for(j=1;j<=n;j++)
{
if(b[j]>max)
max=b[j];
}
cout<<"最大子串和为:"<<max<<endl;
}
//分治法
#include <iostream>
using namespace std;
int maxsum(int a[],int left,int right)
{
int sum=0;
int i,j,s1,s2,lefts,rights,center,leftsum,rightsum;
if(left==right)
{
if(a[left]>0)
sum=a[left];
else
sum=0;
}
else
{
center=(left+right)/2;
leftsum=maxsum(a,left,center);
rightsum=maxsum(a,center+1,right);
s1=0;lefts=0;
for(i=center;i>=left;i--)
{
lefts+=a[i];
if(lefts>s1)
s1=lefts;
}
s2=0;rights=0;
for(j=center+1;j<=right;j++)
{
rights+=a[j];
if(rights>s2)
s2=rights;
}
sum=s1+s2;
if(sum<leftsum)
sum=leftsum;
if(sum<rightsum)
sum=rightsum;
}
return sum;
}
void main()
{
int a[100];
int n,i,l,r;
cout<<"输入序列元素个数:";
cin>>n;
cout<<"输入序列元素:"<<endl;
for(i=1;i<=n;i++)
cin>>a[i];
l=n%2;
r=n-l;
cout<<"最大子段和为:"<<maxsum(a,l,r)<<endl;
}
//动态规划法
#include <iostream>
using namespace std;
void maxsum();
void main()
{
maxsum();
}
void maxsum()
{
int i,j,n,k=1;
int max=0,sum=0;
int a[100],b[100];
cout<<"输入序列元素个数:";
cin>>n;
cout<<"输入元素:"<<endl;
for(i=1;i<=n;i++)
{
cin>>a[i];
}
b[1]=a[1];
for(i=2;i<=n;i++)
{
if(b[i-1]<=0)
b[i]=a[i];
else
b[i]=b[i-1]+a[i];
}
for(j=1;j<=n;j++)
{
if(max<b[j])
{
max=b[j];
}
}
cout<<"最大子段和为:"<<max<<endl; }
测试结果
蛮力法
分治法
动态规划法。

相关文档
最新文档