算法实验3最大子段和问题实验报告Word文档下载推荐.docx
《算法实验3最大子段和问题实验报告Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《算法实验3最大子段和问题实验报告Word文档下载推荐.docx(16页珍藏版)》请在冰豆网上搜索。
1.上机内容
给定有n个整数(可能有负整数)组成的序列(a1,a2,…,an),求改序列形如
的子段和的最大值,当所有整数均为负整数时,其最大子段和为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嵌套所以时间复杂性为○(n3);
分治法设计原理:
1)、划分:
按照平衡子问题的原则,将序列(
,
,…,
)划分成长度相同的两个字序列(
)和(
)。
2)、求解子问题:
对于划分阶段的情况分别的两段可用递归求解,如果最大子段和在两端之间需要分别计算s1=
,s2=
,则s1+s2为最大子段和。
若然只在左边或右边,那就好办了,前者视s1为summax2,后者视s2osummax2。
3)、合并:
比较在划分阶段的3种情况下的最大子段和,取三者之中的较大者为原问题的解。
4)、时间复杂性分析:
f(n)=2*f(n/2)+○(n/2),最后为○(nlogn)。
动态规划法设计原理:
动态规划法求解最大字段和问题的关键是要确定动态规划函数。
记
则
由b(j)的定义,当b(j-1)>
0是,b(j)=b(j-1)+a,否则,b(j)=a。
可得如下递推式:
代码实现过程中只用了一个for,时间复杂性为:
○(n)
(2)对所设计的算法采用大O符号进行时间复杂性分析;
蛮力法时间复杂性为○(n3);
分治法时间复杂性为○(nlogn)
动态规划法时间复杂性为:
(3)上机实现算法,并用计数法和计时法分别测算算法的运行时间;
详情见运行结果。
(4)通过分析对比,得出自己的结论。
结论:
蛮力法只可以处理小理的数据。
当数据量超过10000时,由蛮力法要等很久才输出,所以数据量超过10000时,就比较分治法和动态规划法。
由实验结果可知,动态规划法所用的时间要少。
实验原理图:
三、所用仪器、材料(设备名称、型号、规格等或使用软件)
1台PC及VISUALC++6.0软件。
绘制流程图软件:
DiagramDesigner.
四、实验方法、步骤(或:
程序代码或操作过程)
部分重要代码说明:
#include<
time.h>
//时间的头文件
#include<
math.h>
//数学头文件
intgetMaxSum1(intiarray[],intn)/*蛮力法函数*/
intgetMaxSum2(intiarray[],intstartIndex,intendIndex)//分治法函数
intgetMaxSum3(intiarray[],intn)/*动态规划方法函数*/
intOUT_PRINTF()//输出最大字段求解的函数
intmain()//主函数
iostream>
usingnamespacestd;
/*蛮力法*/
intgetMaxSum1(intiarray[],intn)
{
intmaxSum=0;
//初始化maxSum
for(inti=0;
i<
n;
++i)//实现从第1个数开始计算子段长度为1,2,3…n的子段和
for(intj=i;
j<
++j)
{
inttmp=0;
//初始化tmp(子段和)
for(intk=i;
k<
=j;
++k)
tmp+=iarray[k];
}
if(tmp>
maxSum)//比较子段和,得出最大的子段和maxSum
maxSum=tmp;
}
returnmaxSum;
源程序代码:
/*分治递归方法*/
intgetMaxSum2(intiarray[],intstartIndex,intendIndex)
if(endIndex==startIndex)//只有一个元素
returniarray[startIndex];
if(endIndex-startIndex==1)//两个元素时
inttmp=iarray[startIndex]+iarray[endIndex];
tmp=tmp>
iarray[startIndex]?
tmp:
iarray[startIndex];
iarray[endIndex]?
iarray[endIndex];
returntmp;
//左边一半序列的最大子段和leftMaxSum
intleftMaxSum=getMaxSum2(iarray,startIndex,(startIndex+endIndex)/2);
//右边一半序列的最大子段和rightMaxSum
intrightMaxSum=getMaxSum2(iarray,(startIndex+endIndex)/2+1,endIndex);
ints1=0;
ints2=0;
inttmp=0;
for(inti=(startIndex+endIndex)/2;
i>
=startIndex;
--i)//左子段和
tmp=tmp+iarray[i];
s1)
s1=tmp;
tmp=0;
for(i=(startIndex+endIndex)/2+1;
=endIndex;
++i)//右子段和
s2)
s2=tmp;
intmiddleMaxSum=s1+s2;
intmaxSum=leftMaxSum>
rightMaxSum?
leftMaxSum:
rightMaxSum;
maxSum=maxSum>
middleMaxSum?
maxSum:
middleMaxSum;
returnmaxSum;
/*动态规划方法*/
intgetMaxSum3(intiarray[],intn)
intmaxSum=0;
intb=0;
for(inti=0;
++i)
if(b>
0)
b=b+iarray[i];
else
b=iarray[i];
maxSum)
maxSum=b;
}
intn,i,cho;
clock_tt1,t2,t3,t4,t5,t6;
cout<
<
"
****************************************\n"
;
**求最大字段和问题**\n"
endl;
/*********手动输入,请按1,随机输入请按2*********/\n"
cin>
>
cho;
请输入序列的长度"
n;
int*iarray=newint[n];
if(cho==2)
srand((unsigned)time(NULL));
//cout<
随机序列为:
for(i=1;
i<
=n;
i++)
{
iarray[i]=(rand()/13-1129);
//cout<
"
iarray[i];
}
else
请输入序列"
for(i=0;
t1=clock();
//使用蛮力法求解的开始时间
intmaxSum1=getMaxSum1(iarray,n);
t2=clock();
//蛮力法求解的结束时间
--------------------------------------------------\n"
蛮力法最大子段和为:
<
maxSum1<
endl;
时间:
float(t2-t1)/CLK_TCK<
//CLK_TCK
t3=clock();
//分治法求解的开始时间
intmaxSum2=getMaxSum2(iarray,0,n-1);
t4=clock();
//分治法求解的结束时间
分治法最大子段和为:
maxSum2<
float(t4-t3)/CLK_TCK<
t5=clock();
//动态规划法求解的开始时间
intmaxSum3=getMaxSum3(iarray,n);
t6=clock();
//动态规划法求解的结束时间
动态规划法最大子段和为:
maxSum3<
float(t6-t5)/CLK_TCK<
return0;
inti;
chara,y,Y,b;
OUT_PRINTF();
//调用输出函数
10;
cout<
是否继续输入?
Y/N"
a;
if(a=='
y'
||a=='
Y'
)
OUT_PRINTF();
if(a=='
n'
N'
return0;
五、实验过程原始记录(测试数据、图表、计算等)
测试程序:
输入选择的方式求最大子段和问题。
手动输入适合序列长度短的时候:
当要测试序列长度很大的时候,经过测试,蛮力法的输出时间太长,所以先省去蛮力法的测试。
当序列长度很大是,只调用动态规划法和分治法。
结果如下:
经过测试可知,动态规划法是最佳的选择。
六、实验结果、分析和结论(误差分析与数据处理、成果总结等。
其中,绘制曲线图时必须用计算纸或程序运行结果、改进、收获)
此次实验主要是设计了三种方法来求解最大子段和问题。
在此次实验中遇到过很多问题,如设置循环时,条件不合理,导致没有出来理想中得结果。
还有,为了得出每种方法求解的时间,添加了一个时间函数的头文件,程序中用到了clock()函数,clock()函数计算出来的是硬件滴答的数目,不是毫秒。
在TC2.0中硬件每18.2个滴答是一秒,在VC++6.0中硬件每1000个滴答是一秒。
C/C++中的计时函数是clock(),而与其相关的数据类型是clock_t。
故计算时间的公式为float(ti-ti-1)/CLK_TCK,其中clock_t是用来保存时间的数据类型,在time.h文件中,我们可以找到对它的定义。
用计算机解决复杂的问题,往往把一个大的、复杂的问题根据其功能划分为不同的模块,每一个模块完成一独立的功能.如果每一个模块用计算机语言来实现,那么当所有模块都实现时,即为对复杂问题的解决.最大子段和问题就是一具有独立功能的小模块,在很多大的问题中都涉及到此问题,用不同的算法解决此问题,并分析其优劣。
注:
教师必须按照上述各项内容严格要求,认真批改和评定学生成绩。