最大子段和三种求解方法

最大子段和三种求解方法
最大子段和三种求解方法

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

代码:

#include

using namespace std;

int MaxSum(int a[],int n,int &besti,int &bestj){

int sum=0;

int i,j,k;

for(i=1;i<=n;i++)

for(j=i;j<=n;j++)

{

int thissum=0;

for(k=i;k<=j;k++)thissum+=a[k];

if(thissum>sum){

sum=thissum;

besti=i;

bestj=j;

}

}

return sum;

}

int main(){

int n,a[100],m,i,j,maxsum;

cout<<"请输入整数序列的元素个数n:"<

cin>>n;

cout<<"请输入序列中各元素的值a[i](一共"<

//for(m=1;m<=n;i++)

//cin>>a[m];

for(m=0;m

cin>>a[m];

int b[100];

for(m=0;m

b[m+1]=a[m];

maxsum=MaxSum(b,n,i,j);

cout<<"整数序列的最大子段和是:"<

cout<<"besti="<

cout<<"bestj="<

system("pause");

}

此算法的时间复杂度:O(n3)。

可对此算法进行适当改进,使其时间复杂度变为:O(n2)。

代码:

#include

using namespace std;

int MaxSum(int a[],int n,int &besti,int &bestj){ int sum=0;

int i,j,k;

for(i=1;i<=n;i++){

int thissum=0;

for(j=i;j<=n;j++)

{

thissum+=a[j];

if(thissum>sum){

sum=thissum;

besti=i;

bestj=j;

}

}

}

return sum;

}

int main(){

int n,a[100],m,i,j,maxsum;

cout<<"请输入整数序列的元素个数n:"<

cin>>n;

cout<<"请输入序列中各元素的值a[i](一共"<

//for(m=1;m<=n;i++)

//cin>>a[m];

for(m=0;m

cin>>a[m];

int b[100];

for(m=0;m

b[m+1]=a[m];

maxsum=MaxSum(b,n,i,j);

cout<<"整数序列的最大子段和是:"<

cout<<"besti="<

cout<<"bestj="<

system("pause");

}

2、最大子段和问题的分治法:T(n)=O(nlog(n))。

//最大子段和,分治算法。T(n)=O(nlog(n))。

#include

using namespace std;

int MaxSubSum(int a[],int left,int right){

int sum=0;

if(left==right)sum=a[left]>0?a[left]:0;

else{

int center=(left+right)/2;

int leftsum=MaxSubSum(a,left,center);

int rightsum=MaxSubSum(a,center+1,right);

int s1=0;

int lefts=0;

for(int i=center;i>=left;i--){

lefts+=a[i];

if(lefts>s1)s1=lefts;

}

int s2=0;

int rights=0;

for(int i=center+1;i<=right;i++){

rights+=a[i];

if(rights>s2)s2=rights;

}

sum=s1+s2;

if(sum

if(sum

}

return sum;

}

int main(){

int n,a[100],m,maxsum;

cout<<"请输入整数序列的元素个数n:"<

cin>>n;

cout<<"请输入序列中各元素的值a[i](一共"<

cin>>a[m];

int b[100];

for(m=0;m

b[m+1]=a[m];

maxsum=MaxSubSum(b,1,n);

cout<<"整数序列的最大子段和是:"<

system("pause");

}

3 最大子段和问题的动态规划算法:T(n)=O(n)。

#include

using namespace std;

int MaxSum(int n,int a[]){

int sum=0;

int b=0;

for(int i=1;i<=n;i++){

if(b>0)b+=a[i];

else b=a[i];

if(b>sum)sum=b;

}

return sum;

}

int main(){

int n,a[100],m,maxsum;

cout<<"请输入整数序列的元素个数n:"<

cin>>n;

cout<<"请输入序列中各元素的值a[i](一共"<

cin>>a[m];

int b[100];

for(m=0;m

b[m+1]=a[m];

maxsum=MaxSum(n,b);

cout<<"整数序列的最大子段和是:"<

}

算法分析与设计 实验三 最大子段和问题

昆明理工大学信息工程与自动化学院学生实验报告 ( 201 — 201 学年 第 1 学期 ) 课程名称:算法分析与设计 开课实验室: 年 月 日 一、上机目的及内容 1.上机内容 给定有n 个整数(可能有负整数)组成的序列(a 1,a 2,…,a n ),求改序列形如 ∑=j k k a 1 的子段和的 最大值,当所有整数均为负整数时,其最大子段和为0。 2.上机目的 (1)复习数据结构课程的相关知识,实现课程间的平滑过渡; (2)掌握并应用算法的数学分析和后验分析方法; (3)理解这样一个观点:不同的算法能够解决相同的问题,这些算法的解题思路不同,复杂程度不同,解题效率也不同。 二、实验原理及基本技术路线图(方框原理图或程序流程图) (1)分别用穷举法、分治法和动态规划法设计最大子段和问题的算法; (2)对所设计的算法采用大O 符号进行时间复杂性分析; (3)上机实现算法,并用计数法和计时法分别测算算法的运行时间; (4)通过分析对比,得出自己的结论。 穷举法是用一个二维数组将从i 到j 的和都记录下来,再比较各元素的大小,时间复杂性为O (n 2),分治法的设计思想是不断将问题为子问题,然后求解子问题,最后对解进行合并,时间复杂性为O(nlog n ),动态规划法的设计思想是将问题划分为若干个子问题,时间复杂度为O(n)。

分治法流程图:

穷举法流程图: 动态规划法流程图: 三、所用仪器、材料(设备名称、型号、规格等或使用软件) 1台PC 及VISUAL C++6.0软件

四、实验方法、步骤(或:程序代码或操作过程) 程序代码: //穷举法 #include void main() { int i,j,n; int num[100],a[100],max; printf("\t\t\t 最大子段和问题(穷举法)\n\n"); printf("请输入所要求最大字段和整数的个数:\n"); scanf("%d",&n); printf("请分别输入这%d个整数的值:\n",n); for(i=0;i int MaxSum(int a[],int left,int right) { int sum=0; if (left==right) {

算法练习题-分章节-带答案

算法练习题-分章节-带答案

算法练习题---算法概述 一、选择题 1、下面关于算法的描述,正确的是() A、一个算法只能有一个输入 B、算法只能用框图来表示 C、一个算法的执行步骤可以是无限的 D、一个完整的算法,不管用什么方法来表示,都至少有一个输出结果 2、一位爱好程序设计的同学,想通过程序设计解决“韩信点兵”的问题,他制定的如下工作过程中,更恰当的是() A、设计算法,编写程序,提出问题,运行程序,得到答案 B、分析问题,编写程序,设计算法,运行程序,得到答案 C、分析问题,设计算法,编写程序,运行程序,得到答案 D、设计算法,提出问题,编写程序,运行程序,得到答案 3、下面说法正确的是() A、算法+数据结构=程序 B、算法就是程序 C、数据结构就是程序 D、算法包括数据结构 4、衡量一个算法好坏的标准是()。 A、运行速度快 B、占用空间少 C、时间复杂度低 D、代码短 5、解决一个问题通常有多种方法。若说一个算法“有效”是指( )。 A、这个算法能在一定的时间和空间资源限制内将问题解决 B、这个算法能在人的反应时间内将问题解决 C、这个算法比其他已知算法都更快地将问题解决 D、A和C 6、算法分析中,记号O表示(),记号Ω表示()。 A.渐进下界 B.渐进上界 C.非紧上界 D.非紧下界 7、以下关于渐进记号的性质是正确的有:() A.f(n)(g(n)),g(n)(h(n))f(n)(h(n)) =Θ=Θ?=Θ B.f(n)O(g(n)),g(n)O(h(n))h(n)O(f(n)) ==?= C. O(f(n))+O(g(n)) = O(min{f(n),g(n)}) D.f(n)O(g(n))g(n)O(f(n)) =?=

最大子段和动态规划法

实验名称: 最大子段和问题 实验目的: 了解最大子段和问题 实验环境: 操作系统:Windows XP Professional SP3 机器配置:Intel Pentium4 CPU 3.0GHz , 512MB 内存 开发工具:eclipse 实验内容: 1. 求数列的最大子段和(要求时间复杂为nlogn) (算法设计与分析 吕国英 清华大学出 版社 135页 4..3.3 二分法变异) (分治法) (也可用动态规划算法 参看递归王晓东计算机算法设计与分析第三版p61页) 算法的设计思想: 在对分治法德算法分析中注意到,若记???? ? ? <=<==∑=j i k k a n j i i b ][max ][,1<=j<=n,则所求的 最大子段和为: ][1max ][1max 1max ][1max j b n j k a j i n j k a n j i j i k j i k <=<== <=<=<=<==????? ?<=<=<=∑ ∑== 分为两种情况: (1)、当b[j-1]>0时,b[j]=b[j-1]+a[j]。 (2)、当b[j-1]<0时,b[j]=a[j]。 由此可得计算b[j]的动态规划递归式为: b[j]=max }{][],[]1[j a j a j b +-,1<=j<=n 由分析可知:次算法一共比较了n 次,故: T(n)=O(n)

据此可以写出如下程序: 实验步骤: 程序代码如下: package s; public class Po{ public static void main(String[] args) { int[] a=new int[10]; int[] b=new int[10]; int[] x=new int[10]; int start=0; int end = 0; System.out.print("数组为:");//随机赋值 for(int i =0;i<10;i++){ a[i]=(int)(Math.random()*100-50); System.out.print(a[i]+" "); } System.out.print("\n"); tem(a,x,b); int max=maxSum(a,b,end); System.out.print("最大子段和为:"); System.out.println(max); System.out.print("结束位置为:"); System.out.println(findend(a,b,end)); int begin=findStart(a,b,start,end); System.out.print("开始位置为:"); System.out.println(begin); systemout(x,start,end,a,b); } public static void tem(int a[],int x[],int b[]) {int n=a.length-1; int sum=0; b[0]=x[0];

分治法求最大子段和问题

分治法求最大子段和问题 共有四种方法: 算法一; 算法二; 算法三、Divide and Conquer 算法四源代码、On-line Algorithm 算法一源代码: /*Given (possibly negative) integers A1, A2, …, AN, find the maximum value. 找最大子段和*/ #include #include #include intMaxSubsequenceSum(int A[],int N); main() { inti,N,*A,MaxSum,judge; LARGE_INTEGER begin,end,frequency; //代表64位有符号整数,记录程序运行时间QueryPerformanceFrequency(&frequency);//可以获得当前的处理器的频率 printf("输入整数的个数:"); scanf("%d",&N); A=(int *)malloc(N*sizeof(int)); //用数组给数据动态分配空间 printf("自行输入数据请按1,随机产生数据请按2\n"); scanf("%d",&judge); if(judge==1){ //自行输入数据 printf("输入%d个整数:",N); for(i=0;i

分治法

分治法 【摘要】:分治法可以通俗的解释为:把一片领土分解,分解为若干块小部分,然后一块块地占领征服,被分解的可以是不同的政治派别或是其他什么,然后让他们彼此异化。本文主要叙述了分治法的设计思想及与之有关的递归思想,了解使用分治法解决问题的过程。 【关键词】:分治法分解算法递归二分搜索 Partition Method (Junna Wei) 【abstract 】: the partition method can explain to popular: decomposition, put a slice of territory is decomposed into several pieces of small, then pieces of land occupation of conquest, the decomposition can be different political factions or something, then let them each other alienation. This paper mainly describes the design idea of the partition method and recursive thinking, related to understand the process of solving the problem using the partition method. 【key words 】: partition method decomposition algorithm recursive Binary search 1.引论

最大子序列和的总结

最大子序列和 第一种情况:可以一个不取 【问题描述】:最大子序列和也叫数列的连续最大和,顾名思义,就是在一个长度为n的数列{An}中,求i,j(1<=i<=j<=n),使得数列{An}中,第i个元素到第j个元素之间,所有元素的和最大。例如:-2, 11, -4, 13, -5, -2时答案为20(11 -4 13) 解法一穷举法:以前我想出了一种算法,具体做法是:取出所给序列的所有子序列求和,共分n组,第一组长度为1,有n个;第二组长度为2, 有n-1个;……,最后一组,长度为n,只有一个。比较这n(n+1)/2个序列的和,再将每组的最大值比较,从而得到最大值以及其上下标。 a1 a2 a n-1 a n a1+a2 a2+a3 a n-1+a n a1+a2+a3 a2+a3+a4 ...... ...... ...... a1+a2......+a n-1 a2+a3......+a n a1+a2......+a n-1 +a n 此算法比较直接,也容易写出代码,但其时间开销为O(n2),空间开销为O(n),效率不高。 解法二:动态规划求解, 1 2 F[i]:表示以元素i结尾的连续最大子序列的和 那么对于第i个元素来说,要形成连续的最大子序列,只和相邻的前一个元素有关。因为可以不取,所以如果元素a[i]连接到以元素i-1结尾的最大连续子序列f[i-1]后是负数(f[i-1]+a[i]<0);则宁可不取,这样最大连续子序列和为0。 动态方程: f[i]:=max{0,f[I-1]+a[i]} (边界条件:f[0]=0;) 3、代码1: for I:=1 to n do if (f[I-1]+a[i])>0 then f[i]:=f[I-1]+a[i] else f[i]:=0; max:=-maxlongint; for i:=1 to n do if f[i]>max then max:=f[i];

算法分析实验报告--分治策略

分治策略 姓名:XXX 专业班级:XXX 学号:XXX 指导教师:XXX 完成日期:XXX

一、试验名称:分治策略 (1)写出源程序,并编译运行 (2)详细记录程序调试及运行结果 二、实验目的 (1)了解分治策略算法思想 (2)掌握快速排序、归并排序算法 (3)了解其他分治问题典型算法 三、实验内容 (1)编写一个简单的程序,实现归并排序。 (2)编写一段程序,实现快速排序。 (3)编写程序实现循环赛日程表。设有n=2k个运动员要进行网球循环赛。现 要设计一个满足以下要求的比赛日程表:(1)每个选手必须与其它n-1个选手各赛一次(2)每个选手一天只能赛一场(3)循环赛进行n-1天 四、算法思想分析 (1)编写一个简单的程序,实现归并排序。 将待排序元素分成大小大致相同的2个子集合,分别对2个子集合进行 排序,最终将排好序的子集合合并成为所要求的排好序的集合。 (2)编写一段程序,实现快速排序。 通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有 数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数 据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据 变成有序序列。 (3)编写程序实现循环日赛表。 按分治策略,将所有的选手分为两组,n个选手的比赛日程表就可以通 过为n/2个选手设计的比赛日程表来决定。递归地用对选手进行分割, 直到只剩下2个选手时,比赛日程表的制定就变得很简单。这时只要让

这2个选手进行比赛就可以了。 五、算法源代码及用户程序 (1)编写一个简单的程序,实现归并排序。 #include #include<> #define MAX 10 using namespace std; void merge(int array[],int p,int q,int r) { int i,k; int begin1,end1,begin2,end2; int* temp = new int[r-p+1]; begin1 = p; end1 = q; begin2 = q+1; end2 = r; k = 0; while((begin1 <= end1)&&(begin2 <= end2)) { if(array[begin1] < array[begin2]) { temp[k] = array[begin1]; begin1++; } else { temp[k] = array[begin2]; begin2++; } k++; } while(begin1 <= end1) { temp[k++] = array[begin1++]; }

算法分析习题详细答案五

1.最大子段和问题:给定整数序列 n a a a ,,,21 ,求该序列形如 j i k k a 的子段和 的最大值: j i k k n j i a 1max ,0max 1) 已知一个简单算法如下: int Maxsum(int n,int a,int& best i,int& bestj){ int sum = 0; for (int i=1;i<=n;i++){ int suma = 0; for (int j=i;j<=n;j++){ suma + = a[j]; if (suma > sum){ sum = suma; besti = i; bestj = j; } } } return sum; }试分析该算法的时间复杂性。 2) 试用分治算法解最大子段和问题,并分析算法的时间复杂性。 3) 试说明最大子段和问题具有最优子结构性质,并设计一个动态规划算法解最大子段和问题。分析算法的时间复杂度。 (提示:令1()max ,1,2,,j k i j n k i b j a j n L ) 解:1)分析按照第一章,列出步数统计表,计算可得)(2 n O 2)分治算法:将所给的序列a[1:n]分为两段a [1:n/2]、a[n/2+1:n],分别求出这两段的最大子段和,则a[1:n]的最大子段和有三种可能: ①a[1:n]的最大子段和与a[1:n/2]的最大子段和相同; ②a[1:n]的最大子段和与a[n/2+1:n]的最大子段和相同; ③a[1:n]的最大子段和为两部分的字段和组成,即 j n j i l n i j a a a a a 122;

intMaxSubSum ( int *a, int left , int right){ int sum =0; if( left==right) sum = a[left] > 0? a[ left]:0 ; else {int center = ( left + right) /2; int leftsum =MaxSubSum ( a, left , center) ; int rightsum =MaxSubSum ( a, center +1, right) ; int s_1 =0; int left_sum =0; for ( int i = center ; i >= left; i--){ left_sum + = a [ i ]; if( left_sum > s1) s1 = left_sum; } int s2 =0; int right_sum =0; for ( int i = center +1; i <= right ; i++){ right_sum + = a[ i]; if( right_sum > s2) s2 = right_sum; } sum = s1 + s2; if ( sum < leftsum) sum = leftsum; if ( sum < rightsum) sum = rightsum; } return sum; } int MaxSum2 (int n){ int a; returnMaxSubSum ( a, 1, n) ; } 该算法所需的计算时间T(n)满足典型的分治算法递归分式T(n)=2T(n/2)+O(n),分治算法的时间复杂度为O(nlogn)

最大字段和问题

最大字段和问题 1.实验题目 给定由N 个整数(可能有负整数)组成的序列(1a ,2a ,…,n a ),求该序列形如∑=j i k k a 的子段和的最大值,当所有整数均为负整数是,其最大子段和为0。 2.实验目的 (1)深刻掌握动态规划法的设计思想并能熟练运用; (2)理解这样一个观点:同样的问题可以用不同的方法解决,一个好的算法是反复努力和重新修正的结果。 3.实验分析 蛮力法:利用3个for 的嵌套(实现从第1个数开始计算子段长度为1,2,3…n 的子 段和,同理计算出第2个数开始的长度为1,2,3…n-1的子段和,依次类推到第n 个数开始计算的长为1的子段和)和一个if (用来比较大小),将其所有子段的和计算出来并将最大子段和赋值给summax1。 用了3个for 嵌套所以时间复杂性为○(n 3)。 分治法: (1)划分:按照平衡子问题的原则,将序列(1a ,2a ,…,n a )划分成长度相同的 两个字序列(1a ,…,??2/n a )和(??12/+n a ,…,n a ) 。 (2)求解子问题:对于划分阶段的情况分别的两段可用递归求解,如果最大子段和在 两端之间需要分别计算 s1=?? ??)2/1(max 2/n i a n i k k ≤≤∑=,s2=????)2/(max 12/n j n a j n k k ≤≤∑+=, 则s1+s2为最大子段和。若然只在左边或右边,那就好办了,前者视s1为summax2,后者视s2 o summax2。 (3)合并:比较在划分阶段的3种情况下的最大子段和,取三者之中的较大者为原问 题的解。 (4)时间复杂性分析: f(n) = 2*f(n/2) + ○(n/2), 最后为○(nlogn)。 动态规划法: 动态规划法求解最大字段和问题的关键是要确定动态规划函数。记 )1(max )(1n j a j b i i k k j i ≤≤? ?????=∑=≤≤ 则

最大字段和

最大字段和 【实验目的】 1掌握动态规划法的设计思想并能熟练运用; 2分别用分治法和动态规划法设计最大子段和问题的算法; 【实验设备与环境】 1 PC机一台 2 Turbo C 或VC++ 【实验内容:】 给定由n个整数(可能为负整数)组成的序列a1, a2, …, an,求该序列形如的子段和的最大值,当所有整数均为负整数时定义其最大子段和为0。 【实验方法步骤】 1用分治法求最大子段和 程序代码: #include int MaxSum(int a[],int left,int right) { int i,sum=0; if(left==right) sum=a[left]>0?a[left]:0; else { int center=(left+right)/2; int leftsum=MaxSum(a,left,center); int rightsum=MaxSum(a,center+1,right); int s1=0,s2=0,lefts=0,rights=0; for(i=center;i>=left;i--) { lefts+=a[i]; if(lefts>s1) s1=lefts; }

for(i=center+1;i<=right;i++) { rights+=a[i]; if(rights>s2) s2=rights; } sum=s1+s2; if(sum

算法(复习题)1

平均情况:设待查找的元素在数组中的概率为P,不在数组中的概率为1-P,若出现在数组中每个位置的概率是均等的为p/n T(n)=P1D1+P2D2+...+PiDi+(1-P)Dn+1 =p/2+n(1-p/2) 1.叙述分治算法和动态规划算法的基本思想,并比较两种算法的异同。答:分治法将待求解的问题划分成K个较小规模的子问题,对这K个子问题分别求解,再将子问题的解合并为一个更大规模的问题的解,自底向上逐步求出原问题的解. 动态规划将待求解的问题分解成若干的子问题,自底向上地通过求解子问题的解得到原问题的解。动态规划将每个子问题只求解一次并将其解保存在一个表格中,当需要再次求解此子问题时,只是简单的通过查表过的该子问题的解,避免了大量的重复计算. 异同:分治法求解的问题分解后的子问题都是独立的,而使用动态规划求解的问题分解后得到的子问题往往不是相互独立的。 分治法是自顶向下用递归的方法解决问题,而动态规划则是自底向上非递归解决问题。 1.简述分治算法求解过程的三个阶段。 答:(1)划分:既然是分治,当然需要把规模为n的原问题划分为k个规模较小的子问题,并尽量使这k个子问题的规模大致相同。 (2)求解子问题:各子问题的解法与原问题的解法通常是相同的,可以用递归的方法求解各个子问题,有时递归处理也可以用循环来实现。 (3)合并:把各个子问题的解合并起来,合并的代价因情况不同有很大差异,分治算法的有效性很大程度上依赖于合并的实现。 2.叙述分治法的基本思想,并分析分治法与减治法二者的区别。 答:分治法将待求解的问题划分成K个较小规模的子问题,对这K个子问题分别求解,再将子问题的解合并为一个更大规模的问题的解,自底向上逐步求出原问题的解. 区别:分治法是把一个大问题划分成若干个子问题,分别求解各个子问题,然后把子问题的解进行合并并得到原问题的解。减治法同样是把一个大问题划分成若干个子问题,但是这些子问题不需要分别求解,只需求解其中的一个子问题,因而也无需对子问题的解进行合并。 3.设计分治算法求一个数组中最大元素的位置,建立该算法时间复杂性的 递推式并给出其复杂性的大O表示。 答:设数组a1,a2...an int maxpos(a[],i,j); {if(i==j) return i; mid=(i+j)/2; lmaxpos=maxpos(a,i,mid); rmaxpos=maxpos(a,mid+1,j); if(a[lmaxpos]>=a[rmoxpos]) return lmaxpos; else return rmaxpos;} T(1)=O(n) n=1; T(n)=2T(n/2)+O(1) n>1;

算法分析考试题

1. )(n T 给定数组a[0:n-1],试设计一个算法,在最坏情况下用n+[logn]-2次比较找出 a[0:n-1] 中的元素的最大值和次大值. (算法分析与设计习题 2.16 ) (分治法) a 、 算法思想 用分治法求最大值和次大值首先将问题划分,即将划分成长度相等的两个序列,递归求出左边的最大值次大值,再求出右边的的最大值次大值,比较左右两边,最后得出问题的解。 b 、复杂度分析: 把问题划分为左右两种的情况,需要分别递归求解,时间复杂度可如下计算: 有递推公式为: T(n)=1 n=1 T(n)= 2T(n/2)+1 n>1 所以,分治算法的时间复杂度是n+[logn]-2,当n 为奇数时,logn 取上线,当n 为偶数时,logn 取下线。//不知道为什么会-2! C 、代码实现: #include int a[100]; void maxcmax(int i,int j,int &max,int &cmax) { int lmax,lcmax,rmax,rcmax; int mid; if (i==j) { max=a[i]; cmax=a[i]; } else if (i==j-1) if (a[i]rmax)

if(lcmax>rmax) { max=lmax; cmax=lcmax; } else { max=lmax; cmax=rmax; } else if(rcmax>lmax) { if(rmax==rcmax) { max=rmax; cmax=lmax; } else { max=rmax; cmax=rcmax; } } else { max=rmax; cmax=lmax; } } } int main() { int n; int max,cmax; printf("输入数组长度"); scanf("%d",&n); printf("输入数组:\n"); for(int i=0;i

最大子段和三种求解方法

1、最大子段和问题的简单算法: 代码: #include using namespace std; int MaxSum(int a[],int n,int &besti,int &bestj){ int sum=0; int i,j,k; for(i=1;i<=n;i++) for(j=i;j<=n;j++) { int thissum=0; for(k=i;k<=j;k++)thissum+=a[k]; if(thissum>sum){ sum=thissum; besti=i; bestj=j; } } return sum; } int main(){ int n,a[100],m,i,j,maxsum; cout<<"请输入整数序列的元素个数n:"<>n; cout<<"请输入序列中各元素的值a[i](一共"<>a[m]; for(m=0;m>a[m]; int b[100];

for(m=0;m using namespace std; int MaxSum(int a[],int n,int &besti,int &bestj){ int sum=0; int i,j,k; for(i=1;i<=n;i++){ int thissum=0; for(j=i;j<=n;j++) { thissum+=a[j]; if(thissum>sum){ sum=thissum; besti=i; bestj=j; } } } return sum; }

最大子段和问题实验报告

实验四最大子段和问题 1.实验目的 (1)掌握动态规划的设计思想并能熟练运用; (2)理解这样一个观点:同样的问题可以用不同的方法解决,一个好的算法是反复努力和重新修正的结果; 2.实验要求 (1)分别用蛮力法、分治法和动态规划法设计最大子段和问题的算法; (2)比较不同算法的时间性能; (3)给出测试数据,写出程序文档; 3.实验设备和软件环境 操作系统:Windows 7(64x) 开发工具:Visual Studio 2013 4.实验步骤 以下实验数据都是以数组a[]={-2, 11, -4, 13, -5, -2}为例子; 蛮力法 蛮力法是首先通过两个for循环去求出所有子段的值,然后通过if语句查找出maxsum,返回子序列的最大子段和; 分治法 (1)划分:按照平衡子问题的原则,将序列(a1,a2,…,an)划分成长度相同的两个子序列(a1,a2,...,an/2)和(an/2+1,…,an); (2)求解子问题:对与划分阶段的情况①和②可递归求解,情况③需要分别计算

s1=max{}(1<=i<=n/2),s2=max{}(n/2+1<=j<=n),则s1+s2为情况③的最大子段和。 (3)合并:比较在划分阶段三种情况下的最大子段和,取三者中比较大者为原问题的解。动态规划法划分子问题 (1)划分子问题; (2)确定动态规划函数; (3)填写表格; 分为两种情况: (1)、当b[j-1]>0时,b[j]=b[j-1]+a[j]。 (2)、当b[j-1]<0时,b[j]=a[j] 然后做递归操作求出最大子段和; 5.实验结果 蛮力法 #include #include<> using namespace std; /*------------------------------------------------------------------------------*/ int manlifa(int a[],int x) { int i, j,sum=0,maxsum=0; for (i = 0; i < x; i++) { for (j = i+1; j < x; j++) { sum = a[i]; a[i] += a[j]; if (a[i]>sum) { sum = a[i]; } if (sum>maxsum) { maxsum = sum;

算法分析作业

算法分析练习题(一) 一、选择题 1、二分搜索算法是利用( A )实现的算法。 A、分治策略 B、动态规划法 C、贪心法 D、回溯法 2、下列不是动态规划算法基本步骤的是( A )。 A、找出最优解的性质 B、构造最优解 C、算出最优解 D、定义最优解 3.下列算法中通常以自底向上的方式求解最优解的是( B )。 A、备忘录法 B、动态规划法 C、贪心法 D、回溯法 4、衡量一个算法好坏的标准是(C )。 A 运行速度快 B 占用空间少 C 时间复杂度低 D 代码短 5、以下不可以使用分治法求解的是(D )。 A 棋盘覆盖问题 B 选择问题 C 归并排序 D 0/1背包问题 6. 实现循环赛日程表利用的算法是( A )。 A、分治策略 B、动态规划法 C、贪心法 D、回溯法 7.备忘录方法是那种算法的变形。( B ) A、分治法 B、动态规划法 C、贪心法 D、回溯法8.最长公共子序列算法利用的算法是( B )。 A、分支界限法 B、动态规划法 C、贪心法 D、回溯法9.实现棋盘覆盖算法利用的算法是( A )。 A、分治法 B、动态规划法 C、贪心法 D、回溯法 10. 矩阵连乘问题的算法可由(B)设计实现。 A、分支界限算法 B、动态规划算法 C、贪心算法 D、回溯算法 11、Strassen矩阵乘法是利用( A )实现的算法。 A、分治策略 B、动态规划法 C、贪心法 D、回溯法 12、使用分治法求解不需要满足的条件是(A )。 A 子问题必须是一样的 B 子问题不能够重复

C 子问题的解可以合并 D 原问题和子问题使用相同的方法解 13、下列算法中不能解决0/1背包问题的是(A ) A 贪心法 B 动态规划 C 回溯法 D 分支限界法 14.实现合并排序利用的算法是( A )。 A、分治策略 B、动态规划法 C、贪心法 D、回溯法15.下列是动态规划算法基本要素的是( D )。 A、定义最优解 B、构造最优解 C、算出最优解 D、子问题重叠性质 16.下列算法中通常以自底向下的方式求解最优解的是( B )。 A、分治法 B、动态规划法 C、贪心法 D、回溯法 17、合并排序算法是利用( A )实现的算法。 A、分治策略 B、动态规划法 C、贪心法 D、回溯法 18.实现大整数的乘法是利用的算法( C )。 A、贪心法 B、动态规划法 C、分治策略 D、回溯法 19. 实现最大子段和利用的算法是( B )。 A、分治策略 B、动态规划法 C、贪心法 D、回溯法 20. 一个问题可用动态规划算法或贪心算法求解的关键特征是问题的( B )。 A、重叠子问题 B、最优子结构性质 C、贪心选择性质 D、定义最优解 21. 实现最长公共子序列利用的算法是( B )。 A、分治策略 B、动态规划法 C、贪心法 D、回溯法 二、填空题 1.算法的复杂性有时间复杂性和空间复杂性之分。 2、程序是算法用某种程序设计语言的具体实现。 3、算法的“确定性”指的是组成算法的每条指令是清晰的,无歧义的。 4.矩阵连乘问题的算法可由动态规划设计实现。 5、算法是指解决问题的一种方法或一个过程。

分治算法讲解

分治算法 一:基本概念(分而治之) 分治就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。比如:二分查找,归并排序,快速排序,树的遍历等等 任何一个可以用计算机求解的问题所需的计算时间都与其规模有关。问题的规模越小,越容易直接求解,解题所需的计算时间也越少。例如,对于n个元素的排序问题,当n=1时,不需任何计算。n=2时,只要作一次比较即可排好序。n=3时只要作3次比较即可,…。而当n较大时,问题就不那么容易处理了。要想直接解决一个规模较大的问题,有时是相当困难的。 二:基本思想 分治设计思想:将一个大的问题,分解成一个个小的,相同类型的问题,然后逐个击破各个小问题,最后将小问题逐步合并,得到最终的解。(可能会用到递归,大问题里包含小问题,找到规律然后解决) 分治基本策略:对于一个规模为n的问题,若该问题可以容易地解决(比如说规模n 较小)则直接解决,否则将其分解为k个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。 三:分治使用情况 1) 该问题的规模缩小到一定的程度就可以容易地解决 2) 该问题可以分解为相同类型的小问题(前提) 3) 利用该问题分解出的子问题的解可以合并为该问题的解;(关键) 4) 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。 第三条特征是关键,能否利用分治法完全取决于问题是否具有第三条特征,如果具备了第一条和第二条特征,而不具备第三条特征,则可以考虑用贪心法或动态规划法。 四:基本步骤 (1)划分:把问题的实例划分成子问题 (2)求解:若是子问题比较简单,就直接解决,否则递归求解子问题 (3)合并:合并子问题的解得到原问题的解 课前引导: 一:分段函数 例如:高中数学中的分段函数也是类似分治思想的体现,如看图求y关于x的表达式。一个分段函数,反映的是x与y的关系,简单来说,就是在R的范围内将y的表达式表示出来,那么这时候利用分治的思想,将R区间划分为小区间,然后分别求出各个小区间的表达式,最后合并起来,完成y关于x的表达式的求解 二:大整数乘法 123 345 678 * 3 = 370 037 034 在这里我们可以这样写:

最大子列和

算法分析与设计实验报告 拓展实验1

} 算法1结果: 算法2结果:

附录:完整代码 #include #include #include using namespace std; 算法3 结果: 算法4结果:

intDivideAndconquer(int[],int,int); constint Max=20; int MaxQSum4(int[],int&,int&,int&); intmain(){ inti,x,m,n,Maxsum,a[Max]; cout<<"请输入序列元素个数:"<>x; srand(time(0)); for( i=0;i50) a[i]=-(rand()%50); cout<max&&sum>0) max=sum; } } if( max==a[0]&&max<0 ) max=0; return max; } */ /*部分穷举 O=n*n int MaxQSum2( int a[Max],int&x){ int max=a[0],sum; for( inti=0;imax&&sum>0)

算法:动态规划解决最大子段和问题

算法:动态规划解决最大子段和问题 /* 动态规划法思想:将较大的问题分解成较小的问题,先求解子问题,然后通过子问题的解得到原问题的解,经过分解的子问题之间并不是 相互独立的。*/ # include # include # include int max_sum(int a[],int n,int *best_i,int *best_j) { // *best_i表示最大子段和的起始下标 // *best_j表示最大子段和的终点下标 // i,j 表示当前子段的起点和终点下标 int i,j; int this_sum[100]; int sum[100]; int max=0; this_sum[0]=0; sum[0]=0; *best_i=0; *best_j=0; i=1; for(j=1;j<=n;j++) { if(this_sum[j-1]>=0) //判断是否为负数 this_sum[j]=this_sum[j-1]+a[j]; else { this_sum[j]=a[j]; i=j; } //如果子段和数组前一个大于下一个元素 if(this_sum[j]<=sum[j-1]) sum[j]=sum[j-1]; //对当前子段和赋值 else { sum[j]=this_sum[j]; *best_i=i; *best_j=j; max=sum[j]; } }

return max; } void main() { int i,j,n,a[100],t; printf("请输入数列的个数(<99):\n"); scanf("%d",&n); printf("请输入数列元素:\n"); for(i=1;i<=n;i++) scanf("%d",&a[i]); i=j=1; t=max_sum(a,n,&i,&j); printf("最大字段和是:%d\n",t); printf("字段起点是:%d\n",i); printf("字段结束点:%d\n",j); }

相关文档
最新文档