//生成递增随机数列
array[i]=array[i-1]+1+rand()%3+rand()%10;
}
产生要查找的数的下标
suffix为要搜索的元素下标
intsuffix=rand()%j;
key为要查找的数据
intkey=array[suffix];
2、统计理论平均查找次数和实际平均查找次数
floatcount=0.0//平均实际查找次数
根据二分查找的算法可得理论平均查找次数为O(logn);
3、二分查找
intBinarySearch(intb[],intkey,intleft,intright){
while(left<=right){
middle=(left+right)/2;
if(Key==b[middle]){
RowCount++;
returnmiddle;
}
elseif(key
right=middle-1;
RowCount++;
}
else{
left=middle+1;
RowCount++;
}
}
return-1;//没有找到
}
五、运行结果
x:
数组个数y:
平均查找时间系列1:
理论平均查找时间系列2:
实际平均查找时间
六、实验分析与讨论
在试验中,遇到了如何产生随机数递增数组的问题,解决方法是采用rand()函数获得随机递增数组和要查找的数字下标。
采用随机化的数组,能够更加具有普遍性,更加能够证明算法的平均查找时间。
七、实验心得
二分查找在搜索有序表时,效率比较高。
通过这次实验我对二分查找算法的认识又有了新的提高。
指导教师对实验报告的评语
成绩:
指导教师签字:
年月日
算法分析与设计实验报告
—分治法解决棋盘覆盖问题
一、实验目的
建立算法复杂度的理论分析与实验分析的联系,深刻体会算法复杂度作为算法的好坏评价指标的本质含义。
二、实验要求
1、用c++程序语言实现分治法解决棋盘覆盖问题。
2、分析算法的时间复杂度
三、实验原理
用分治策略,可以设计解决棋盘问题的一个简介算法。
当k>0时,可以将2^k*2^k棋盘分割为4个2^k-1*2^k-1子棋盘。
由棋盘覆盖问题得知,特殊方格必位于4个较小的子棋盘中,其余3个子棋盘中无特殊方格。
为了将3个无特殊方格的子棋盘转化为特殊棋盘可以将一个L型骨牌覆盖这3个较小棋盘的会合处,所以,这3个子棋盘上被L型覆盖的方格就成为给棋盘上的特殊方格,从而将原问题转化为4个较小规模的棋盘覆盖问题。
递归的使用这种分割,直至棋盘简化为1*1棋盘为止。
四、实验过程(步骤)
1、数据说明:
tr:
棋盘上左上角方格的行号
tc:
棋盘上左上角方格的列号
dr:
特殊方格所在的行号
dc:
特殊方格所在的列号
定义了全局变量tile,用于进行覆盖。
区分4种不同L类型的骨牌,初始值为0.
Board[]数组用来表示棋盘
2、函数说明
ChessBoard函数实现了递归的将棋盘划分为子棋盘,并将棋盘进行覆盖。
main()函数用来进行输入棋盘的大小和特殊棋盘的位置。
使用memset(Board,0,sizeof(Board))将Board[]数组清零
使用setw()函数控制输出格式
五、运行结果
六、实验分析与讨论
设T(n)是算法ChessBoard覆盖一个2^k*2^k棋盘所需要的时间,则从算法的分治策略可知,T(k)满足如下递归方程:
O
(1)k=0
T(k)={
4T(k-1)+O
(1)k>0
解得此递归方程可得T(k)=O(4^k)。
由于覆盖一个2^k*2^k棋盘所需的L型骨牌个数为(4^k—1)/3,故算法ChessBoard是一个在渐进意义下最优的算法
七、实验心得
通过这次试验,更多的了解了分治法解题的思路就是将大问题化为若干子问题,再依次解决子问题,最后获得问题的答案。
是我更加熟练地使用分治策略解决问题。
指导教师对实验报告的评语
成绩:
指导教师签字:
年月日
算法分析与设计实验报告
——0-1背包问题的动态规划算法的实现
一、实验目的
建立算法复杂度的理论分析与实验分析的联系,深刻体会算法复杂度作为算法的好坏评价指标的本质含义。
二、实验要求
1、用c++语言实现0-1背包问题的动态规划算法。
2、分析0—1背包问题动态规划算法的时间复杂度并提出优化建议。
三、实验原理
动态规划算法的基本思想是将待求解的问题分解成若干相关不独立的子问题,先求解子问题,然后从这些子问题的解得到原问题的解。
用一个表存储已解决的子问题的答案,不管该问题是否被用到,只要被计算过,就存入表中。
这样我们就可以在多项式时间内在表中找到需要的已求得的答案,避免了大量的重复计算。
这就是动态规划算法的基本思想。
四、实验过程(步骤)
1、最优解结构分析及递归式
由于动态规划解决的问题多数有重叠子问题这个特点,为减少重复计算,对每一个子问题只解一次,将其不同阶段的不同状态保存在一个二维数组中。
设所给0-1背包问题的子问题
的最优值为m(i,j),即m(i,j)是背包容量为j,可选择物品为i,i+1,…,n时0-1背包问题的最优值。
由0-1背包问题的最优子结构性质,可以建立计算m(i,j)的递归式如下。
此时背包容量为j,可选择物品为i。
此时在对xi作出决策之后,问题处于两种状态之一:
(1)背包剩余容量是j,没产生任何效益;
(2)剩余容量j-wi,效益值增长了vi;
2、数据说明:
N:
物品个数
C:
背包容量
W[]:
物品重量数组
V[]:
物品价值数组
3、函数说明
voidKnapsack(int*v,int*w,intc,intn,intm[][C+1])计算所给出的0-1背包问题的最优解
voidTraceback(intm[][C+1],int*w,intc,intn,int*x)根据函数Knapsack()计算出的m[][]数组计算出最优解,并输出结果。
intmin(intx,inty)比较大小并返回较小的值;
intmaxintx,inty)比较大小并返回较大的值;
五、运行结果
六、实验分析与讨论
按上述算法Krapsack计算后,m[1][c]所给出要求的0-1背包问题的最优值。
相应的最优解可有函数Tracback()根据m[][]数组计算得出。
计算复杂性分析:
从计算m(i,j)的递归式看出,函数Knapsack需要O(nc)计算出时间,函数Traceback需要O(n)计算时间。
算法Knapsack有两个较明显的缺点。
其一是算法要求所给的物品的重量必须是整数,其次,当背包容量c很大时,算法需要的计算时间较多。
当c>2^n时,算法Knapsack需要Ω(n2^n)计算时间。
七、实验心得
使用动态规划算法用于解0-1背包问题,比穷举法具有相当好的效率。
由于0-1背包的时间复杂度为O(2^n),所以是一个NP难问题,可以通过计算跳跃点的方式转变为计算复杂度为多项式时间内的算法,从而对算法进行了优化。
这次实验用到的是动态规划法,0-1背包问题用动态规划法首先要构造动态规划表,用三个for语句实现;根据动态规划表每行的最大值变化确定每个元素的装入与否,逐步确定出装入背包的物品,背包容量的最大值也就是动态规划表最右下角。
通过这次试验更加熟悉了动态规划算法的原理以及使用。
指导教师对实验报告的评语
成绩:
指导教师签字:
年月日
算法分析与设计实验报告
——背包问题的贪心算法的实现
一、实验目的
建立算法复杂度的理论分析与实验分析的联系,深刻体会算法复杂度作为算法的好坏评价指标的本质含义。
二、实验要求
1、用c++语言实现背包问题的贪心算法。
2、分析算法的计算复杂性并验证能否得到最优解
三、实验原理
贪心算法总是做出在当前看来是最好的选择。
贪心算法并不从整体最优上加以考虑,它总是做出的选择只是在某种意义上的局部最优选择。
贪心法解决背包问题的基本步骤:
首先计算每种物品单位重量的价值v/w,然后,依贪心选择策略,将尽可能多的单位重量价值最高的物品装入背包。
若将这种物品全部装入背包后,背包内的物品总重量未超过才,则选择单位重量价值次高的物品并尽可能多的装入背包。
以此策略一直进行下去,直到背包装满为止。
五、实验过程(步骤)
数据说明:
N:
物品数量c:
背包容量
V[]:
物品价值数组m[]:
物品重量数组x[]:
物品放入背包的重量
函数说明:
VoidKnapsack(intn,floatc,floatw[],floatx[])用来计算最大价值
Sort(intn,floatv[],floatw[])用来计算单位重量价值的物品,并从大到小进行排序。
五、运行结果
七、实验分析与讨论
Knapsack算法的主要计算时间在于将个物品依其单位重量的价值从大到小排序。
因此,算法的计算时间上界为O(nlogn)。
贪心算法不能得到最优解的验证
对于0-1背包问题,贪心选择之所以不能得到最优解是因为在这种情况下,无法保证最终能将背包装满,部分闲置的背包空间使每千克背包空间的价值降低了,因此不能得到最优解。
八、实验心得
通过这次试验我明白了贪心算法对与具有某些最优子结构性质的问题具有很高的效率,在做这次试验过程中,也体会到了贪心算法和动态规划解问题的不同点,在动态规划算法中,每一步所做的选择往往依赖于相关子问题的解。
因而只有在解出相关子问题以后,才做出选择。
贪心算法可以依赖于以往所做过的选择,但决不依赖于将来所做的选择,也不依赖于子问题的解,是一种自顶向下的方式进行。
指导教师对实验报告的评语
成绩:
指导教师签字:
年月日
算法分析与设计实验报告
——最小重量机器设计回溯法解决
一、实验目的
建立算法复杂度的理论分析与实验分析的联系,深刻体会算法复杂度作为算法的好坏评价指标的本质含义。
二、实验要求
1、用c++语言实现最小重量机器设计的回溯算法。
2、分析算法的计算复杂性
三、实验原理
回溯法的基本思想:
首先,应该明确的确定问题的解空间。
确定了解空间的组织结构后,觳觫发从开始节点(根节点)出发,以深度优先方式搜索整个解空间。
这个开始结点成为活结点,同时也成为当前的扩展结点。
在当前的扩展结点处,向纵深方向搜索移至一个新的结点。
这个新结点成为新的活结点,并成为新的扩展结点。
如果在当前的扩展结点处不能再向纵深方向移动,则当前扩展结点成为死结点。
此时,应往回移动(回溯)至最近的活结点,并使这个活结点成为当前的扩展结点。
回溯以这种工作方式递归的在解空间中搜索,直至找到所要求的解或解空间中已无活结点为止。
六、实验过程(步骤)
解题思路:
由于题目已经给出总价格的上限,因此算法通过使用回溯来选择合适的机器使得在总价格不超过d时得到的机器重量最小。
首先初始化当前价格cp=0,当前重量cw=0,此外,还要设置一个变量sum表示选择机器的总重量,初始化其为每个部件从1号供应商购买的重量。
在循环选择i号机器时,判断从j号供应商购买机器后的价格是否大于总价格,如果不大于则选择,否则不选,继续选择下一供应商进行判断。
在得到一个合适的供应商后,继续选择下一机器的供应商,从第一个选到最后一个供应商。
当所有机器选择结束后,判断得到的总重量是否比之前的sum小,如果小就赋给sum,然后从这一步开始,回溯到上一机器,选择下一合适供应商,继续搜索可行解,直到将整个排列树搜索完毕。
这样,最终得到的sum即为最优解。
数据说明:
N:
零件数量m:
不同的零件商
W[][]:
是从供应商j处购得的部件i的重量c[][]:
相应的价值
算法设计:
a.部件有n个,供应商有m个,分别用w[i][j]和c[i][j]存储从供应商j处购得的部件i的重量和相应价格,d为总价格的上限。
b.用递归函数backtrack(i)来实现回溯法搜索排列树(形式参数i表示递归深度)。
①若cp>d,则为不可行解,剪去相应子树,返回到i-1层继续执行。
②若cw>=sum,则不是最优解,剪去相应子树,返回到i-1层继续执行。
③若i>n,则算法搜索到一个叶结点,用sum对最优解进行记录,返回到i-1层继续执行;
④用for循环对部件i从m个不同的供应商购得的情况进行选择(1≤j≤m)。
c.主函数调用一次Knapsack
(1)即可完成整个回溯搜索过程,最终得到的sum即为所求最小总重量。
五、运行结果
六、实验心得
通过这次试验我明白了回溯法的思想,回溯法借助想象出来的树的结构,把问题简单化,使得解问题更方便。
通过剪枝函数和约束函数对于求问题的解有很大的帮助,但要把一些限制条件把剪枝函数抽象化。
指导教师对实验报告的评语
成绩:
指导教师签字:
年月日
算法分析与设计实验报告
——最小重量机器设计分支限界法解决
二、实验目的
建立算法复杂度的理论分析与实验分析的联系,深刻体会算法复杂度作为算法的好坏评价指标的本质含义。
三、实验要求
1、用c++语言实现最小重量机器设计的分支限界算法。
2、分析算法的计算复杂性
三、实验原理
分支限界法以广度优先或以最小耗费优先的方式搜索解空间。
搜索策略是,在扩展结点处,先生成其所有的儿子结点(分支),然后再从当前当前的活结点表中选择下一个扩展节点。
为有效的选择下一扩展节点,加速搜索的进程,在每一或节点处,计算一个函数值(限界),并根据函数值,从当前活结点表中选择一个有利于的节点作为扩展节点,使搜索朝着解空间上最优解的分支推进,以便尽快找出一个最优解
七、实验过程(步骤)
用分支定界法解题的一般步骤:
在解最小机器重量问题的优先队列式分支定界法中,活结点优先队列中结点元素N的优先级由该结点的重量给出,重量最小的为小顶堆堆顶元素,堆元素的类型为HeapNode,其私有成员有weight,level,对于任意活结点N.weight所相应的重量;
函数AddLive将一个新的活结点插入到子集树和优先队列中。
算法中N是当前的扩展结点,cw是相应的重量,cp是相应的价值,while循环不断的扩展结点,直到子集树的叶结点成为扩展结点为止。
此时优先队列中所有活结点的都考察完了,故,该叶结点相应的解为问题的最优解。
While内部循环,算法首先检查当前儿子结点的可行性,如果可行,则加入到子集树和活结点队列中。
五、运行结果
六、实验心得
通过做这次试验,深刻体会到了堆所起到的作用和分支限界法求解问题的效率在很大情况下高于回溯法,由于访问树方式的不同,使得分支定界法对每个结点只有一次成为可扩展结点,而回溯法则不同。
错误!
未找到目录项。