第一篇:算法和算法的描述观课报告
《算法和算法的描述》观课报告
通过观看周思博老师讲授的《算法和算法的描述》一课,我收获颇丰。周老师所体现出的对课堂的掌控能力、扎实的专业知识和过硬的教学基本功,令我折服。整堂课,学生能够积极参与,课堂气氛活跃,很好的体现出快乐课堂效率课堂的特点,下面我就自己的收获谈几点观课感想。
一、导入环节引人入胜
通过“过河”游戏导入新课,可以快速地吸引学生的注意力,激发学生的学习兴趣,充分调动学生学习的主动性。学生在玩的过程中轻松直观的解决了“如何过河”,从而通过亲身体验获得解决问题的方法与步骤——算法的概念,学生也在老师的异动下轻松地掌握了算法的概念,将原本抽象地概念通过游戏赋予了形象化。
二、教学方法灵活多样
在教学过程中,周老师采用了游戏激趣、成功体验激趣、直观教学激趣等方式方法,激发学生的学习兴趣,唤起了学生的学习欲望,从中激发学生学习兴趣。开展小组活动,小组成员对共同学习中发现的问题,利用教师所提供的感性材料,通过分析、比较、抽象和概括与一系列积极的思维活动,实现了认识上的飞跃。小组活动不仅为每个学生表达自己的看法创造机会,而且有利于培养学生的团队精神和创新能力。着重加强了师生互动,想方设法激发学生主动求知的意识和积极进取的精神,给学生创设了自主、合作、探究学习的时间和空间,教好地培养了学生敢于质疑、乐于交流与合作、善于探究的学习习惯。
三、教学案例设计精心。
这节课课堂实例选取典型,分析讨论了生活中的实例,“比较大小”案例让学生知道如何比较两数的大小,“交换酒杯”案例让学生知道如何交换两个变量的值,“累加求和”案例让学生体会累加器的使用。在这三个案例中,第一个案例采用教师展示,学生评论的方法;第二个案例教师仅展示算法,学生动手绘制流程图;第三个案例学生自己描述算法并绘制流程图。由简单到复杂,难度循序渐进,以巩固算法的描述方法。整个教学过程体现了以教师为主导,学生为主体的教学理念,把课堂让给学生,让学生活跃于课堂,去发现问题,解决问题。
四、总结归纳
在课堂小结环节中,周老师利用思维导图的方式回顾本节课知识点。将不同的知识点相互联系起来。让学生形成清晰的知识脉络。
学习了周老师的这节课,我获益匪浅。今后在我的课堂中,我会更加注重教学设计,突出重难点,选取合适的教学策略,学生更高效的上好每一节课。
第二篇:算法和算法描述教案
一、教学内容:算法和算法的描述(选修1算法与程序设计 广东教育出版社)
二、教学课时:1课时
三、教学地点:计算机室2
四、教学目标:
1、知识目标
(1)明白算法的概念,理解算法的特征。(2)掌握算法描述的三种方法,能看懂流程图。(3)了解算法的意义,找出三种算法描述的优缺点。
2、技能目标
(1)知道在什么场合应该用什么算法描述。
(2)能对算法和算法的描述正确定位,能用算法解决实际问题,为学习后面的程序设计打下基础。
3、情感目标
(1)能把现实社会中的问题用算法描述出来,培养学生们的合作精神和想象能力,以提高学生们的信息素养。
五、教学方法:任务驱动法
六、教学重点:
算法的概念、描述算法的三种方法。
七、教学难点:
用流程图描述算法。
八、教学过程
1.激发兴趣、创设情景
这节课内容主要是一些概念和理论,而算法的概念和理论都太抽象,讲起来非常的枯燥乏味,那么就要把这些抽象的东西变得通俗易懂,使学生能轻松而又愉快的接受并理解。
举出一个例子如炒土豆丝如何做?引导学生们一步步说出步骤,最后教师总结:算法就是解决问题的方法和步骤。在以后的编程中也要记住了,有些步骤是可以颠倒的,不影响程序的结果;但是有些一但颠倒了那最终的结果也就全变了。
2.讲.解
激发学生的兴趣后对算法、算法的特征(确定性、有穷性)进行讲解,注意运用生活中的实例,以便让学生们理解。
讲述算法的三种描述方法:自然语言、流程图、伪代码。学生们比较熟悉的是自然语言,陌生难理解的是流程图和伪代码。
先带学生们了解自然语言,然后讲伪代码,讲完伪代码后,引导学生们如何把这些程序用流程图表示出来。流程图的基本图形及其功能
给出一个程序,让学生们先读这个程序,再用流程图表示这个程序如:
Private Sub Command1_Click()a = InputBox(“输入数字”)If a Mod 2 = 0 Then Print a & “是偶数” Else Print a & “是奇数” End If End Sub 学生们自学后,由教师引导发现这是一个判断奇偶数的程序,找一个学生展示他的流程图,然后大家共同检查这个流程图是否正确。
九、课堂作业 再给学生们一个程序,让学生们读并且在word中画出流程图,然后教到主机上。
十、课后反思:
在本节课中进行任务驱动式教学,充分发挥学生的主观能动性。同时这节课内容多,而且难以理解,练习生活中的实例,既可以激发学生们的兴趣,又有助于知识的迁移和内化。
第三篇:算法实验报告
《算法设计与分析》
实验报告
班级
姓名
学号
****年**月**日
目录
实验一
二分查找程序实现…………………………………………………………………03页
实验二
棋盘覆盖问题(分治法).…………………………………………………………08页
实验三
0-1背包问题的动态规划算法设计……………………………………………….11页
实验四
背包问题的贪心算法………………………………………………………………14页
实验五
最小重量机器设计问题(回溯法)………………………………………………17页
实验六
最小重量机器设计问题(分支限界法)…………………………………………20页
指导教师对实验报告的评语
成绩:
指导教师签字:
****年**月**日
实验一:二分查找程序实现
一、实验时间:2013年10月8日,星期二,第一、二节地点:J13#328
二、实验目的及要求
目的:
建立算法复杂度的理论分析与实验分析的联系,深刻体会算法复杂度作为算法的好坏评价指标的本质含义。要求:
1、用c/c++语言实现二分搜索算法。
2、通过随机产生有序表的方法,测出在平均意义下算法比较次数随问题规模的变化曲线,并作图。
三、实验环境
平台:Win7 32位操作系统 开发工具:Codeblocks10.05
四、实验内容
对已经排好序的n个元素a[0:n-1],现在要在这n个元素中找出一特定元素x。
五、算法描述及实验步骤
算法描述:
折半查找法也称为二分查找法,它充分利用了元素间的次序关系,采用分治策略,可在最坏的情况下用O(log n)完成搜索任务。它的基本思想是,将n个元素分成个数大致相同的两半,取a[n/2]与欲查找的x作比较,如果x=a[n/2]则找到x,算法终止。如果xa[n/2],则我们只要在数组a的右半部继续搜索x。二分搜索法的应用极其广泛,而且它的思想易于理解。确定算法复杂度基本步骤:
1、首先设定问题规模n;
2、随即产生递增数列;
3、在n个有序数中随机取一个作为待查找量,搜索之;
4、记录查找过程中的比较次数,再次生成新的有序表并查找,记录查找次数,每个数组重复10次;
5、改变问题规模n重复上述步骤2~4,n取100、200……1000;
6、依实验数据作图,并与理论图作比较;
7、二分搜索算法平均查找次数: 问题规模为n时,平均查找次数为: A(n)=Int(logn)+ 1/2 // Int()函数为向下取整
即二分搜索算法对于含有n个数据的有序表L平均作了约Int(logn)+1/2次的查找操作。
实验步骤:
1.初始化生成递增随机数列: for(int j=100;j <=1000;j+=100){
array[0]=10+rand()%15;
for(int i=1;i array[i]=array[i-1]+1+rand()%3+rand()%10; } } 2.定义二分查找算法: int BinarySearch(const int b[], int searchKey, int low, int high);其中,返回值为int类型,数组b[]为待查递增序列,searchKey为所查数据,low为数组b[]左下标,hight为数组b[]右下标。该算法实现过程为: 将数组b[]的n个元素分成个数大致相同的两半,取b[n/2]与searchKey作比较。如果searchKey=b[n/2],则找到searchKey,算法终止;如果searchKeyb[n/2],则只要在数组b的右半部继续搜索searchKey。 3.实现主函数并完成所有代码。4.算法复杂性分析: 容易看出,没执行一次算法的while循环,待搜索数组的大小减少一半。因此,在最坏情况下,while循环被执行了O(logn)次。循环体内运算需要O(1)时间,因此整个算法在最坏情况下的计算时间复杂性为O(logn)。 六、调试过程及实验结果 输出结果为: Every array repeat search times: 10 Number of Elements 理论平均查找次数 实际平均查找次数 6.5 6.1 200 7.5 7.3 300 8.5 7.4 400 8.5 7.4 500 8.5 7.5 600 9.5 8.2 700 9.5 8.8 800 9.5 8.7 900 9.5 8.8 1000 9.5 9.4 七、总结 二分查找在搜索有序表时,效率比较高。通过这次实验我对二分查找算法的认识又有了新的提高。本想写个图形界面,但由于种种原因,没有实现,下次做加密算法时,要写一个图形化界面。 指导教师对实验报告的评语 成绩: 指导教师签字: ****年**月**日 实验二:分治法解决棋盘问题 一、实验时间:2013年10月22日,星期二,第一、二节地点:J13#328 二、实验目的及要求 1、用c/c++语言实现分治法解决棋盘问题算法。 2、实现棋盘化以及棋盘覆盖 三、实验环境 Windows 2007 操作系统 以及code blocks软件 四、实验内容 在一个2^k*2^k的方格组成的棋盘中,若恰有一个方格与其他方格不同,则称该方格为一个特殊方格。用分治法将整个棋盘除特殊方格以外的方格覆盖。 五、算法描述及实验步骤 将2^k x 2^k的棋盘,先分成相等的四块子棋盘,其中特殊方格位于四个中的一个,构造剩下没特殊方格三个子棋盘,将他们中的也假一个方格设为特殊方格。如果是: 左上的子棋盘(若不存在特殊方格)----则将该子棋盘右下角的那个方格假设为特殊方格 右上的子棋盘(若不存在特殊方格)----则将该子棋盘左下角的那个方格假设为特殊方格 左下的子棋盘(若不存在特殊方格)----则将该子棋盘右上角的那个方格假设为特殊方格 右下的子棋盘(若不存在特殊方格)----则将该子棋盘左上角的那个方格假设为特殊方格 当然上面四种,只可能且必定只有三个成立,那三个假设的特殊方格刚好构成一个L型骨架,我们可以给它们作上相同的标记。这样四个子棋盘就分别都和原来的大棋盘类似,我们就可以用递归算法解决。 六、调试过程及实验结果 七、总结 由于覆盖一个2k*2k棋盘所需的L型骨牌个数为(4k-1)/3,故此算法是一个在渐近意义下最优的算法。 指导教师对实验报告的评语 成绩: 指导教师签字: ****年**月**日 实验三:0-1背包问题的动态规划算法设计 一、实验目的及要求 1.了解并掌握动态规划算法的设计思想。 2.利用动态规划算法的设计思想实现0-1背包问题的算法设计。 二、实验环境 使用C++语言; 在windows环境下使用CodeBlocks调试并运行。 三、实验内容 1.了解并掌握动态规划的设计思想。 2.利用动态规划算法的思想解决0-1背包问题。 四、算法描述及实验步骤 每种物品一件,可以选择放1或不放0。 用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是: f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]} “将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”,价值为f[i-1][v];如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。 五、调试过程及实验结果 六、总结 0-1背包问题是最基本的背包问题,它包含了背包问题中设计状态、方程的最基本思想,另外,别的类型的背包问题往往也可以转换成0-1背包问题求解。通过这次实验我对动态规划算法的认识又有了新的提高。 指导教师对实验报告的评语 成绩: 指导教师签字: ****年**月**日 实验四:背包问题的贪心算法 一、实验目的: 运用贪心算法思想,设计解决上述问题的算法,找出最大背包价值的装法。 二、实验要求 1.用c++语言实现背包问题的贪心算法。 2.掌握贪心思想的应用。 三、实验原理 在贪心算法中采用逐步构造最优解的办法,在每个阶段,都做出一个看上去最优的决策(在一定的标准下),决策一旦做出就不可更改。 四、实验过程(步骤)1.定义背包结构体: struct stone { int name;int weight;//物品的剩余重量 int weight_t;//物品的重量 float benefit;//物品的价值 //float b;};2.定义函数void sort(stone *data,int num)//计算物品的单位重量的价值,并进行排序 3.定义主函数并完成贪心选择。4.分析算法复杂性分析: 该算法的主要计算时间在于将各种物品依其单位重量的价值从大到小排序。因此,算法的计算时间上界为O(n*logn)。 与0-1背包问题类似,所不同的是在选择物品i装入背包时,可以选择物品i的一部分,可以选择物品i 可以选择物品 的一部分,而不一定要全部装入背包,1≤i≤n。这2类问题都具有最优子结构,最优子结构性质,极为相似,但 最优子结构 背包问题可以用贪心算法求解,而0-1背包问题却不能用贪心算法求解。 五、运行结果 六、实验分析与讨论 贪心法的基本思路: ——从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。当达到某算法中的某一步不能再继续前进时,算法停止。该算法存在问题: 1.不能保证求得的最后解是最佳的; 2.不能用来求最大或最小解问题; 3.只能求满足某些约束条件的可行解的范围。实现该算法的过程: 1.Begin 从问题的某一初始解出发; 2.while 能朝给定总目标前进一步 do 3.求出可行解的一个解元素; 4.由所有解元素组合成问题的一个可行解 七、实验心得 贪心算法通过一系列的选择来得知问题的解,它所做的每一个选择都是当前状态下局部最好选择,即贪心选择。通过背包问题的解决,进一步掌握了贪心算法的思想,并能在解问题时灵活运用。 指导教师对实验报告的评语 成绩: 指导教师签字: ****年**月**日 实验五:最小重量机器设计问题(回溯法) 一、实验目的 建立算法复杂度的理论分析与实验分析的联系,深刻体会算法复杂度作为算法的好坏评价指标的本质含义。 二、实验要求 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即为所求最小总重量。 五、运行结果 六、实验心得 通过这次试验我明白了回溯法的思想,回溯法借助想象出来的树的结构,把问题简单化,使得解问题更方便。通过剪枝函数和约束函数对于求问题的解有很大的帮助,但要把一些限制条件把剪枝函数抽象化。 指导教师对实验报告的评语 成绩: 指导教师签字: ****年**月**日 实验六:最小重量机器设计问题(分支限界法) 一、实验时间:2013年11月12日,星期二,第一、二节地点:J13#328 二、实验目的及要求 1、了解分支限界法的基本思想。 2、运用分支限界法解决最小重量机器设计问题。 三、实验环境 平台:win7操作系统 开发工具:codeblocks10.05 四、实验内容 最小重量机器设计问题:设某一机器由n个部件组成,每一种部件可以从m个不同的供应商处购得。设wij是从供应商j处购得的部件i的重量,cij是相应的价格。试设计一个算法,给出总价格不超过c的最小重量机器设计 五、算法描述及实验步骤 算法描述: 解空间为一棵排列树,采用优先队列式分支限界法找出所给的最小重量机器设计,开始时,将排列树的根节点置为当前扩展结点。在初始扩展结点处还设有选定部件是哪个供应商提供的,故cv=0,cw=0,position=0,peer=0,1≤i≤n。x[1:n]记录供应商的选择while完成对排列树内部结点的有序扩展。循环体内依次从活结点优先队列中取出具有最小重量的结点,依次为当前扩展结点。并且花费不超过c并加以扩展,队列为空时则结束循环。当peer=n时,此时扩展结点是叶节点,得到当前的最小重量和最优解数组x。若peer 实验步骤: 1.定义一个优先队列LinkQueue: void InitQueue(LinkQueue &Q);//创建一个队列-----首尾结点 void DestroyQueue(LinkQueue &Q);//销毁一个队列 void ClearQueue(LinkQueue &Q);//清空队列 int QueueEmpty(LinkQueue &Q);//判断队列是否为空,空则返回TURE,否则返回FLASE int QueueLength(LinkQueue &Q);//求队列的长度 void EnQueue(LinkQueue &Q,QElemType &e);//拆入e为新的队尾元素 void DeQueue(LinkQueue &Q,QElemType &e);//用e返回队列的对头元素 bool IsEmpty(LinkQueue &Q)//判断队列是否为空 2.定义类MinWeight,实现函数有: void Add(int wt,int ct,int i);//往队列插入节点 int FindBest();//实现最小重量机器的查找 void setMW();//函数初始化 void printMW();//打印输出结果 3 实现主函数并完成所有代码。 六、调试过程及实验结果 七、总结 利用分支限界法解决最小重量机器问题,就是构造一个优先队列,按照规定的优先级按最大效益优先的方式查找解空间树,找出满足要求的最优解。通过利用分支限界法解决最小重量机器问题,熟练了对分支限界法的使用。 指导教师对实验报告的评语 成绩: 指导教师签字: ****年**月**日 算法分块总结 为备战2005年11月4日成都一战,特将已经做过的题目按算法分块做一个全面详细的总结,主要突出算法思路,尽量选取有代表性的题目,尽量做到算法的全面性,不漏任何ACM可能涉及的算法思路。算法设计中,时刻都要牢记要减少冗余,要以简洁高效为追求目标。另外当遇到陌生的问题时,要想方设法进行模型简化,转化,转化成我们熟悉的东西。 图论模型的应用 分层图思想的应用: 用此思想可以建立起更简洁、严谨的数学模型,进而很容易得到有效算法。重要的是,新建立的图有一些很好的性质: 由于层是由复制得到的,所以所有层都非常相似,以至于我们只要在逻辑上分出层的概念即可,根本不用在程序中进行新层的存储,甚至几乎不需要花时间去处理。由于层之间的相似性,很多计算结果都是相同的。所以我们只需对这些计算进行一次,把结果存起来,而不需要反复计算。如此看来,虽然看起来图变大了,但实际上问题的规模并没有变大。层之间是拓扑有序的。这也就意味着在层之间可以很容易实现递推等处理,为发现有效算法打下了良好的基础。 这些特点说明这个分层图思想还是很有潜力的,尤其是各层有很多公共计算结果这一点,有可能大大消除冗余计算,进而降低算法时间复杂度。二分图最大及完备匹配的应用: ZOJ place the robots: 二分图最优匹配的应用: 最大网络流算法的应用:典型应用就求图的最小割。最小费用最大流的应用: 容量有上下界的最大流的应用: 欧拉路以及欧拉回路的应用:主要利用求欧拉路的套圈算法。最小生成树: 求最小生成树,比较常用的算法有Prim算法和Kruskal算法。前者借助Fibonacci堆可以使复杂度降为O(Vlog2V+E),后者一般应用于稀疏图,其时间复杂度为O(Elog2V)。最小K度限制生成树: 抽象成数学模型就是: 设G=(V,E,ω)是连通的无向图,v0 ∈V是特别指定的一个顶点,k为给定的一个正整数。首先考虑边界情况。先求出问题有解时k 的最小值:把v0点从图中删去后,图中可能会出 现m 个连通分量,而这m 个连通分量必须通过v0来连接,所以,在图G 的所有生成树中 dT(v0)≥m。也就是说,当k 首先,将 v0和与之关联的边分别从图中删去,此时的图可能不再连通,对各个连通分量,分别求最小生成树。接着,对于每个连通分量V’,求一点v1,v1∈V’,且ω(v0,v1)=min{ω(v0,v’)|v’∈V’},则该连通分量通过边(v1,v0)与v0相连。于是,我们就得到了一个m度限制生成树,不难证明,这就是最小m度限制生成树。这一步的时间复杂度为O(Vlog2V+E)我们所求的树是无根树,为了解题的简便,把该树转化成以v0为根的有根树。 假设已经得到了最小p度限制生成树,如何求最小p+1 度限制生成树呢?在原先的树中加入一条与v0相关联的边后,必定形成一个环。若想得到一棵p+1 度限制生成树,需删去一条在环上的且与v0无关联的边。删去的边的权值越大,则所得到的生成树的权值和就越小。动态规划就有了用武之地。设Best(v)为路径v0—v上与v0无关联且权值最大的边。定义father(v)为v的父结点,动态转移方程:Best(v)=max(Best(father(v)),(father(v),v)),边界条件为Best[v0]=-∞,Best[v’]=-∞|(v0,v’)∈E(T)。 状态共|V|个,状态转移的时间复杂度O(1),所以总的时间复杂度为O(V)。故由最小p度限制生成树得到最小p+1度限制生成树的时间复杂度为O(V)。1 先求出最小m度限制生成树; 2由最小m度限制生成树得到最小m+1度限制生成树;3 当dT(v0)=k时停止。 加边和去边过程,利用动态规划优化特别值得注意。 次小生成树: 加边和去边很值得注意。 每加入一条不在树上的边,总能形成一个环,只有删去环上的一条边,才能保证交换后仍然是生成树,而删去边的权值越大,新得到的生成树的权值和越小。具体做法: 首先做一步预处理,求出树上每两个结点之间的路径上的权值最大的边,然后,枚举图中不在树上的边,有了刚才的预处理,我们就可以用O(1)的时间得到形成的环上的权值最大的边。如何预处理呢?因为这是一棵树,所以并不需要什么高深的算法,只要简单的BFS 即可。 最短路径的应用: Dijkstra 算法应用: Folyed 算法应用: Bellman-Ford 算法的应用: 差分约束系统的应用: 搜索算法 搜索对象和搜索顺序的选取最为重要。一些麻烦题,要注意利用数据有序化,要找一个较优的搜索出发点,凡是能用高效算法的地方尽量争取用高效算法。基本的递归回溯深搜,记忆化搜索,注意剪枝: 广搜(BFS)的应用: 枚举思想的应用: ZOJ 1252 island of logic A*算法的应用: IDA*算法的应用,以及跳跃式搜索探索: 限深搜索,限次: 迭代加深搜索: 部分搜索+高效算法(比如二分匹配,动态规划): ZOJ milk bottle data: 剪枝优化探索: 可行性剪枝,最优性剪枝,调整搜索顺序是常用的优化手段。 动态规划 动态规划最重要的就是状态的选取,以及状态转移方程,另外还要考虑高效的预处理(以便更好更快的实现状态转移)。最常用的思想就是用枚举最后一次操作。 状态压缩DP,又叫带集合的动态规划:题目特点是有一维的维数特别小。类似TSP问题的DP: 状态划分比较困难的题目: 树形DP: 四边形不等式的应用探索:四边形不等式通常应用是把O(n^3)复杂度O(n^2) 高档数据结构的应用 并查集的应用: 巧用并查集中的路径压缩思想: 堆的利用: 线段树的应用: 总结用线段树解题的方法 根据题目要求将一个区间建成线段树,一般的题目都需要对坐标离散。建树时,不要拘泥于线段树这个名字而只将线段建树,只要是表示区间,而且区间是由单位元素(可以是一个点、线段、或数组中一个值)组成的,都可以建线段树;不要拘泥于一维,根据题目要求可以建立面积树、体积树等等 树的每个节点根据题目所需,设置变量记录要求的值 用树形结构来维护这些变量:如果是求总数,则是左右儿子总数之和加上本节点的总数,如果要求最值,则是左右儿子的最大值再联系本区间。利用每次插入、删除时,都只对O(logL)个节点修改这个特点,在O(logL)的时间内维护修改后相关节点的变量。 在非规则删除操作和大规模修改数据操作中,要灵活的运用子树的收缩与叶子节点的释放,避免重复操作。 Trie的应用:; Trie图的应用探索: 后缀数组的应用研究: 在字符串处理当中,后缀树和后缀数组都是非常有力的工具,其中后缀树了解得比较多,关于后缀数组则很少见于国内的资料。其实后缀数组是后缀树的一个非常精巧的替代品,它比后缀树容易编程实现,能够实现后缀树的很多功能而时间复杂度也不太逊色,并且,它比后缀树所占用的空间小很多。 树状数组的应用探索:; 计算几何 掌握基本算法的实现。凸包的应用:; 半平面交算法的应用:; 几何+模拟类题目:几何设计好算法,模拟控制好精度。扫描法:; 转化法:ZOJ 1606 将求所围的格子数,巧妙的转化为求多边形的面积。离散法思想的应用:; 经典算法:找平面上的最近点对。 贪心 矩形切割 二分思想应用 活用经典算法 利用归并排序算法思想求数列的逆序对数: 利用快速排序算法思想,查询N个数中的第K小数: 博弈问题 博弈类题目通常用三类解法:第一类推结论; 第二类递推,找N位置,P位置; 第三类SG函数的应用。第四类极大极小法,甚至配合上αβ剪枝。最难掌握的就是第四类极大极小法。 第一类:推结论。典型题目: 第二类:递推。典型题目: 比如有向无环图类型的博弈。在一个有向图中,我们把选手I有必胜策略的初始位置称为N位置(Next player winning),其余的位置被称为P位置(Previous player winning)。很显然,P位置和N位置应该具有如下性质: 1. 所有的结束位置都是P位置。 2. 对于每一个N位置,至少存在一种移动可以将棋子移动到一个P位置。3. 对于每一个P位置,它的每一种移动都会将棋子移到一个N位置。 这样,获胜的策略就是每次都把棋子移动到一个P位置,因为在一个P位置,你的对手只能将棋子移动到一个N位置,然后你总有一种方法再把棋子移动到一个P位置。一直这样移动,最后你一定会将棋子移动到一个结束位置(结束位置是P位置),这时你的对手将无法在移动棋子,你便赢得了胜利。 与此同时,得到了这些性质,我们便很容易通过倒退的方法求出哪些位置是P位置,哪些位置是N位置,具体的算法为: 1. 将所有的结束位置标为P位置。 2. 将所有能一步到达P位置的点标为N位置。 3. 找出所有只能到达N位置的点,将它们标为P位置。 4. 如果在第三步中没有找到新的被标为P位置的点,则算法结束,否则转到步骤2。这样我们便确定了所有位置,对于题目给出的任一初始位置,我们都能够很快确定出是选手I获胜还是选手II获胜了。第三类:SG函数的应用。 关于SG函数的基本知识:对于一个有向图(X, F)来说,SG函数g是一个在X上的函数,并且它返回一个非负整数值,具体定义为 g(x)min{n0,ng(y)对于所有yF(x)} 1. 对于所有的结束位置x,g(x)= 0。 2. 对于每一个g(x)≠ 0的位置x,在它可以一步到达的位置中至少存在一个位置y使得g(y)= 0。 3.对于每一个g(x)= 0的位置x,所有可以由它一步到达的位置y都有g(y)≠ 0。 定理 如果g(xi)是第i个有向图的SG函数值,i = 1,…,n,那么在由这n个有向图组成的状态的SG函数值g(x1,…xn)= g(x1)xor g(x2)xor … xor g(xn) 第四类:极大极小法。 典型题目:ZOJ 1155:Triangle War ZOJ 1993:A Number Game 矩阵妙用 矩阵最基本的妙用就是利用快速乘法O(logn)来求解递推关系(最基本的就是求Fibonacci数列的某项)和各种图形变换,以及利用高斯消元法变成阶梯矩阵。典型题目: 数学模型举例 向量思想的应用: UVA 10089:注意降维和向量的规范化 ; 利用复数思想进行向量旋转。 UVA 10253: 递推 数代集合 数代集合的思想: ACM ICPC 2002-2003, Northeastern European Region, Northern Subregion 中有一题:Intuitionistic Logic 用枚举+数代集合思想优化,注意到题中有一句话:“You may assume that the number H = |H| of elements of Hdoesn't exceed 100”,这句话告诉我们H的元素个数不会超过100,因此可以考虑用一个数代替一个集合,首先把所有的运算结果都用预处理算出来,到计算的时候只要用O(1)的复杂度就可以完成一次运算。 组合数学 Polya定理则是解决同构染色计数问题的有力工具。 补集转化思想 ZOJ 单色三角形: 字符串相关 扩展的KMP算法应用:;最长回文串; 最长公共子串; 最长公共前缀; 填充问题 高精度运算 三维空间问题专题 无论什么问题,一旦扩展到三难空间,就变得很有难度了。三维空间的问题,很考代码实现能力。 其它问题的心得 解决一些判断同构问题的方法:同构的关键在于一一对应,而如果枚举一一对应的关系,时间复杂度相当的高,利用最小表示,就能把一个事物的本质表示出来。求最小表示时,我们一定要仔细分析,将一切能区分两个元素的条件都在最小表示中体现,而且又不能主观的加上其他条件。得到最小表示后,我们往往还要寻求适当的、高效的匹配算法(例如KMP字符匹配之类的),来比较最小表示是否相同,这里常常要将我们熟悉的高效算法进行推广 算法设计与分析学习心得 班级:物联网1201 姓名:刘潇 学号:1030612129 一、实验内容: 这学期的算法与设计课,老师布置了这四个问题,分别是货郎担问题,动态生成二维数组,对话框下拉列表,排序问题。 二、学习掌握: 基本程序描述: (1)货郎担问题:货郎担问题属于易于描述但难于解决的著名难题之一,至今世界上还有不少人在研究它。货郎担问题要从图g的所有周游路线中求取具有最小成本的周游路线,而由始点出发的周游路线一共有(n一1)!条,即等于除始结点外的n一1个结点的排列数,因此货郎担问题是一个排列问题。货郎担的程序实现了利用穷举法解决货郎担问题,可以在城市个数和各地费用给定的情况下利用穷举法逐一计算出每一条路线的费用,并从中选出费用最小的路线。从而求出问题的解 (2)费用矩阵:费用矩阵的主要内容是动态生成二维数组。首先由键盘输入自然数,费用矩阵的元素由随机数产生,并取整,把生成的矩阵存放在二维数组中,最后把矩阵内容输出到文件和屏幕上。它采用分支界限法,分支限界法的基本思想是对包含具有约束条件的最优化问题的所有可行解的解(数目有限)空间进行搜索。该算法在具体执行时,把全部可行的解空间不断分割为越来越小的子集,并为每个子集内的解计算一个下界或上界。动态生成二维n*n的数组程序利用指针表示数组的行和列,并逐一分配空间,在输入n的数值后,系统自动分配空间,生成n*n的数组,并产生随机数填充数组,最后将结果输入到指定文件中。 三.疑问与总结: 货郎担的问题,我认为穷举法相对比而言是比较初级的方法,费时耗力,适合在练习时选用,但是在实际问题中不建议采用。克鲁斯卡尔或者普里姆算法求取最小生成树的方法来解决货郎担的问题是更适合现实解决问题的。我认为程序可以用switch函数来将函数分成几个部分更人性化,比如分为解决问题的的选项,输出结果选项,退出程序选项等。再有就是费用矩阵的值可以从文件中读取,而结果也可以直接放在指定文件中,这样在实际应用中比较广泛。 动态生成二维数组的程序我认为如果按照规范性,我的方法是中规中矩的,毕竟再向下延伸,生成三维的数组,需要三层的指针来实现。但是就程序的简化程度和计算机处理时间来说,我认为这样双层指针的算法有些太占用内存,毕竟要给行和列各分配n个空间。我通过与同学的交流,我发现可以用1位数组来实现二维的n*n的数组。首先分配n*n的空间,然后通过循环在一行的数据达到n时自动换行。这样程序得到了一定的简化,并且减少了一定的内存使用。我认为这种方法是比较贴合实际的。 四.心得体会 在计算机软件专业中,算法分析与设计是一门非常重要的课程,很多人为它如痴如醉。很多问题的解决,程序的编写都要依赖它,在软件还是面向过程的阶段,就有程序=算法+数据结构这个公式。算法的学习对于培养一个人的逻辑思维能力是有极大帮助的,它可以培养我们养成思考分析问题,解决问题的能力。 如果一个算法有缺陷,或不适合某个问题,执行这个算法将不会解决这个问题。不同的算法可能用不同的时间、空间或效率来完成同样的任务。一个算法的优劣可以用空间复杂性和时间复杂度来衡量。算法可以使用自然语言、伪代码、流程图等多种不同的方法来描述。计算机系统中的操作系统、语言编译系统、数据库管理系统以及各种各样的计算机应用系统中的软件,都必须使用具体的算法来实现。算法设计与分析是计算机科学与技术的一个核心问题。因此,学习算法无疑会增强自己的竞争力,提高自己的修为,为自己增彩。篇二:算法个人心得 算法学习心得: 算法这个词是在我在大学第一次c语言课上听到的,当时老师讲的是程序=算法+数据结构,算法是一个程序的灵魂。当时我什么也不懂,不知道什么叫数据结构,什么叫算法,它们是干什么的我也不明白。然而经历了大学四年的学习,现在的我对算法有了一个较为清晰的认识,对于它的作用也有了深刻的体会。 所谓算法简单来说就是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,也就是说算法告诉计算机怎么做,以此来解决问题。同一个问题存在多种算法来解决它,但是这些算法存在着优劣之分,好的算法速度快,效率高,占用空间小,差的算法不仅复杂难懂,而且效率低,对机器要求还高,当然,有时候算法之间存在一种互补关系,有些算法效率高,节省时间,但浪费空间,另外一些算法可能速度上慢些,但是空间比较节约,这时候我们就应该根据实际要求,和具体情况来采取相应的算法来解决问题。 这学期算法课上我们主要讲了七部分内容.第一章主要讲的是算法的基本概念,算法时间复杂度分析,算法的渐近时间复杂度等内容。因为算法之间的比较就是通过时间复杂度和空间复杂度来来比较的,第一章的主要目的就是让我们学会去分析一个算法的复杂度,以后就可以通过对复杂度的分析来评价算法的好坏。 第二章讲的是分治法,任何一个可以用计算机求解的问题所需的计算时间都与其规模有关。问题的规模越小,越容易直接求解,解题所需的计算时间也越少,分治法的设计思想就是,将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。在这一章中我们讲到了寻找第k个元素,矩阵相乘,寻找最近点对等几个使用分治法的经典例子,最后还将讲到了傅里叶变换的问题。以前我们学到的归并排序,二分搜索其实也是基于分治法思想的。能采用分治法来解决的问题通常有如下几个特征: 1)该问题的规模缩小到一定的程度就可以容易地解决 2)该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子 结构性质。 3)利用该问题分解出的子问题的解可以合并为该问题的解; 4)该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公 共的子子问题。 在用分治法解决实际问题时,我们疑问究竟各个子问题的规模应该怎样才为适当?从大量实践中发现,在用分治法设计算法时,最好使子问题的规模大致相同。换句话说,将一个问题分成大小相等的k个子问题的处理方法是行之有效的,这就是一种平衡的思想。 第三章主要讲动态规划问题。这一章的内容我觉得是算法设计思想中最难,也最有趣的这部分。什么叫动态规划,动态规划的思想是什么?动态规划采用自顶向下的方式分析问题,自底向上的方式递推求值,将待求解的问题分解成若干个子问题,先求解子问题,并把子问题的解存储起来以便以后用来计算所需要求的解。简言之,动态规划的基本思想就是把全局的问题化为局部的问题,为了全局最优必须局部最优。“多阶段决策问题是根据问题本身的特点,将其求解的过程划分为若干个相互独立又相互联系的阶段,在每一个阶段都需要做出决策,并且在一个阶段的决策确定以后再转移到下一个阶段,在每一阶段选取其最优决策,从而实现整个过程总体决策最优的目的”(引用)。还记得期末考试中的最后一道关于任意给定一个数,从所给的牌中用最少的牌组成这个数,这个问题其实就可以用动态规划来解决。本科期间,在算法课上老师在动态规划这一章不布置的一个作业跟这个题目类似,当时的题目是找钱问题,问题是这样描述的:有n种不同面值的硬币,各硬币面值存于数组t[1:n],现用这些面值的钱来找钱,编程计算找钱m的最少硬币数及各个面值。分析如下:假设对于i = 1...n-1,所需最少的硬币数count(i)已知,那么对于n,所需的硬币数为min(count(i)+ count(n-i)), i=1...n-1;于是一个直观的方法是用递归计算。 但是,递归过程中,每次计算count(i),都会重复计算 count(1)....count(i-1);这样时间复杂度就是o(n^2);我们可以从1开始记录下每个钱数所需的硬币枚数,避免重复计算,为了能够输出硬币序列,我们还需要记录下每次新加入的硬币。下面给出用动态规划解决此问题的递推式: 参数说明: 当只用面值为t[1],t[2],„t[n]来找出钱j时,所用的硬币的最小个数记为c(i,j),则c(i,j)的递推方程为: 运用这个递推式,我们可以从下往上记录各个j所需要的应兵书i,最后当j=m时,所对应的i就是我们要求的。第四章讲的是集合算法,这一章的内容是我第一次接触,以前没有学过。这一章主要讲了平摊分析,union-find,finding the depth,以及2-3树等内容,平摊分析教会我们如何从整体的角度去更精确的分析算法的时间复杂度,union-find sets是一种简单的用途广泛的集合,并查集是若干个不相交集合,能够实现较快的合并和判断元素所在集合的操作,一般采取树形结构来存储并查集,并利用一个rank数组来存储集合的深度下界,在查找操作时进行路径压缩使后续的查找操作加速,finding the depth 确定深度问题。为了既能求得各点在原先树中的正确深度、又能使时间复杂度较小,需要使用具有路径压缩功能的find-depth指令,同时还需要采取一些辅助手段来保证深度计算的正确性。2-3树具有以下几个特点: 1、任一内结点(非叶结点)均有2个或3个儿子。 2、从根到每片树叶的路径长度相等。 3、内结点中只存放便于查找的信息,而叶结点中存放原始数据。 第五章主要讲了随机算法。在随机算法中,我们不要求算法对所有可能的输入均正确计算,只要求出现错误的可能性小到可以忽略的程度。另外我们也不要求对同一输入算法每次执行时给出相同的结果。我们所关心的是算法在执行时,是否能够产生真正随机的结果。有不少问题,目前只有效率很差的确定性求解算法,但用随机算法去求解,可以很快地获得相当可信的结果。随机算法通常分为两大类:las vegas算法、monte carlo算法。las vegas算法总是给出正确的结果,但在少数应用中,可能出现求不出解的情况。此时需再次调用算法进行计算,直到获得解为止.mont carlo算法通常不能保证计算出的结果总是正确,一般只能断定所给解的正确性不小于p(1/2<p<1)。通过反复执行算法(即以增大算法的执行时间为代价),能够使发生错误的概率小到可以忽略的程度。第五章还讲到素数测试,其中介绍了相关定理,重点讲了miller-rabin算法。 第六章介绍了计算模型,这一章主要介绍了有关计算的一些本质问题,random access machines(随机存取机,简称ram),存储程序模型rasp(random access stored program),图灵机(turning machine)以及各个计算模型之间的关系。 第七章介绍了np完全问题,主要包括近似算法(approximation algorithms),非确定性turing机 ndtm,确定性turing机 dtm,以及之间的区别,np完全经典问题等内容。 经过一学期的算法学习,我对算法的了解进一步加深,曾经学习过的内容得到进一步巩固,同时没有接触的内容也让我有了新的认识。作为一名计算机专业的学生,算法是一门基础学科,它里面包含的思想无处不在,学好算法分析,对于在自己的方向上获得启示,体会更深有着重大作用。所以,我们应该培养对算法的兴趣,将算法的运用融入到生活当中,比如找钱问题就是个很好的例子,通过具体的生活实例来让算法变得更加有魅力,有吸引力,以此来激发对算法的兴趣。篇三:算法设计与分析学习总结 算法分析与设计 学习总结 题目:算法分析与设计学习总结 学 院 信息科学与工程学院 专 业 届 次 学生姓名 学 号 二○一三年一月十五日 算法分析与设计学习总结 本学期通过学习算法分析与设计课程,了解到:算法是一系列解决问题的清晰指令,代表着用系统的方法描述解决问题的策略机制。算法能够对一定规范的输入,在有限时间内获得所要求的输出。如果一个算法有缺陷,或不适合某个问题,执行这个算法将不会解决这个问题。不同的算法可能用不同的时间、空间或效率来完成同样的任务。一个算法的优劣可以用空间复杂性和时间复杂度来衡量。算法可以使用自然语言、伪代码、流程图等多种不同的方法来描述。计算机系统中的操作系统、语言编译系统、数据库管理系统以及各种各样的计算机应用系统中的软件,都必须使用具体的算法来实现。算法设计与分析是计算机科学与技术的一个核心问题。 设计的算法要具有以下的特征才能有效的完成设计要求,算法的特征有:(1)有穷性。算法在执行有限步后必须终止。(2)确定性。算法的每一个步骤必须有确切的定义。(3)输入。一个算法有0个或多个输入,作为算法开始执行前的初始值,或初始状态。(4)输出。一个算法有一个或多个输出,以反映对输入数据加工后的结果。没有输出的算法是毫无意义的。(5)可行性。在有限时间内完成计算过程。 算法设计的整个过程,可以包含对问题需求的说明、数学模型的拟制、算法的详细设计、算法的正确性验证、算法的实现、算法分析、程序测试和文档资料的编制。算法可大致分为基本算法、数据结构的算法、数论与 代数算法、计算几何的算法、图论的算法、动态规划以及数值分析、加密算法、排序算法、检索算法和并行算法。经典的算法主要有: 1、穷举搜索法 穷举搜索法是对可能是解的众多候选解按某种顺序进行逐一枚举和检验,bing从中找出那些符合要求的候选解作为问题的解。 穷举算法特点是算法简单,但运行时所花费的时间量大。有些问题所列举书来的情况数目会大得惊人,就是用高速计算机运行,其等待运行结果的时间也将使人无法忍受。我们在用穷举算法解决问题是,应尽可能将明显不符合条件的情况排除在外,以尽快取得问题的解。 2、迭代算法 迭代法是数值分析中通过从一个初始估计出发寻找一系列近似解来解决问题(一般是解方程或方程组)的过程,为实现这一过程所使用的方法统称为迭代法。迭代法是用于求方程或方程组近似根的一种常用的算法设计方法。设方程为f(x)=0,用某种数学方法导出等价的形式x=g(x),然后按以下步骤执行: (1)选一个方程的近似根,赋给变量x0。(2)将x0的值保存于变量x1,然后计算g(x1),并将结果存于变量x0。(3)当x0与x1的差的绝对值还小于指定的精度要求时,重复步骤(2)的计算。若方程有根,并且用上述方法计算出来的近似根序列收敛,则按上述方法求得的x0就认为是方程的根。 3、递推算法 递推算法是利用问题本身所具有的一种递推关系求问题解的一种方法。它把问题分成若干步,找出相邻几步的关系,从而达到目的。 4、递归算法 递归算法是一种直接或间接的调用自身的算法。 能采用递归描述的算法通常有这样的特征:为求解规模为n的问题,设法将它分解成规模较小的问题,然后从这些小问题的解方便地构造出大问题的解,并且这些规模较小的问题也能采用同样的分解和综合方法,分解成规模更小的问题,并从这些更小问题的解构造出规 模较大问题的解。特别的,当规模n=0或1时,能直接得解。 递归算法解决问题的特点有: (1)递归就是在过程或函数里调用自身 (2)在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口 (3)递归算法解题通常显得很简洁,但递归算法解题的运行效率较低 (4)在递归调用的过程中系统为每一层的返回点、局部变量等开辟堆栈来存 储。 举例如下: fibonacci数列 int fib[50];//采用数组保存中间结果 void fibonacci(int n){ fib[0] = 1;fib[1] = 1;for(int i=2;i<=n;i++)fib[i] = fib[i-1]+fib[i-2];} 5、分治算法 分治算法是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题,直到最后子问题可以简单地直接求解,原问题的解即子问题解的合并。 如果原问题可分割成k个子问题,且这些子问题都可解,并可利用这些子问题的解求出原问题的解,那么这种分治法就是可行的。由分治法产生的子问题往往是原问题的较小模式,这就为使用递归技术提供了方便。在这种情况下,反复应用分治手段,可以使子问题与原问题类型一致而其规模却不断缩小,最终使子问题缩小到很容易直接求出其解。这自然导致递归过程的产生。分治与递归像一对孪生兄弟,经常同时应用在算法设计之中,并由此产生许多高效算法。 分治策略的算法设计模式 divide_and_conquer(p){ if(|p|<=n0)return adhoc(p); divide p into smaller substances p1,p2,„,pk; for(i=1;i<=k;k++)yi=divide-and-conquer(pi)//递归解决pi return merge(y1,y2,„,yk)//合并子问题 } 6、贪心算法 贪心算法也称贪婪算法。它在对问题求解时,总是做出在当前看来是最好的选择。它不从整体最优上考虑,所得出的仅是在某种意义上的局部最优解。贪心算法的基本思路如下:(1)建立数学模型来描述问题 (2)把求解的问题分成若干个子问题 (3)对每一子问题求解,得到子问题的局部最优解 (4)把子问题的局部最优解合成原来问题的一个解 贪心算法的一般流程: greedy(a){ s={ };//初始解集合为空集 while(not solution(s))//集合s没有构成问题的一个解 { x = select(a);//在候选集合a中做贪心选择 if feasible(s, x)//判断集合s中加入x后的解是否可行 s = s+{x};a = a-{x};} return s;} (1)候选集合a:问题的最终解均取自于候选集合a。(2)解集合s:解集合s不断扩展,直到构成满足问题的完整解。 (3)解决函数solution:检查解集合s是否构成问题的完整解。 (4)选择函数select:贪心策略,这是贪心算法的关键。 (5)可行函数feasible:解集合扩展后是否满足约束条件。 7、动态规划算法 动态规划算法是一种在数学和计算机科学中用于求解包含重叠子问题的最优化问题的方法。其基本思想是,将原问题分解为相似的子问题,在求解的过程中通过子问题的解求出原问题的解。 动态规划算法的步骤 (1)找出最优解的性质,并刻画其结构特征;(2)递归地定义最优值(写出动态规划方程);(3)以自底向上的方式计算出最优值;(4)根据算法最优值时得到的信息,构造一个最优值。 动态规划算法的有效性依赖于问题本身所具有的两个重要的性质:最优子结构性质和子问题重叠性质。(1)最优子结构:当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质。 (2)重叠子问题:在用递归算法自顶向下解问题时,每次产生的子问题并不总是新问题,有些子问题被反复计算多次。 8、回溯算法 回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。当探索到某一步时,发现原先的选择并不优或达不到目标,就回退一步重新选择,这种走不通就退回再走的技术成为回溯法,满足回溯条件的某个状态的点称为“回溯点”。迷宫问题算法所采用的就是回溯算法。 回溯算法解决问题的过程是先选择某一可能的线索进行试探,每一步试探都有多种方式,将每一方式都一一试探,如有问题就返回纠正,反复进行这种试探在反复纠正,直到得出全部符合条件的答案或是问题无解为止。由于回溯方法的本质是深度优先的方法在解的空间树中搜索,就要从堆栈中找到回溯的前一个位置继续试探。 装载问题回溯算法数据结构 #define num 100 int n;//集装箱的数量 int c;//轮船的载重量 int w[num];//集装箱的重量数组 int x[num];//当前搜索的解向量 int r;//剩余集装箱的重量 int cw;//当前轮船的载重量 int bestw;//当前最优载重量 int bestx[num];//当前最优解 算法实现 //形参表示搜索第t层结点 void backtrack(int t){ //到达叶子结点 if(t>n){ //更新最优解 if(cw>bestw){ for(int i=1;i<=n;i++)bestx[i] = x[i];bestw = cw;} return;} //更新剩余集装箱的重量 r-= w[t];//搜索左子树 if(cw+w[t]<=c){ x[t] = 1;cw += w[t];backtrack(t+1);cw-= w[t];} //搜索右子树 if(cw+r>bestw){ x[t]=0;backtrack(t+1);} r += w[t];//恢复状态 } 9、分支限界算法 分支限界算法是一种在表示问题解空间的树上进行系统搜索的方法。该方法使用了广度篇四:算法设计与实现个人课程总结 算法课程总结 指导教师 所在院(系) 班 级 学生姓名 学 号 一、算法概述 1.什么是算法? 算法是解一确定类问题的任意一种特殊的方法。在计算机科学中,算法是使用计算机解一类问题的精确、有效方法的代名词。算法是一组有穷的规则,它规定了解决某一特定类型问题的一系列运算。 2.算法的五个重要特性:确定性、能行性、输入、输出、有穷性/有限性。1)确定性:算法每种运算必须有确切定义,不能有二义性。2)能行性:算法中有待实现的运算都是基本的运算,原理上每种运算都能由人用纸和笔在有限的时间内完成。3)输入:每个算法有0个或多个输入。这些输入是在算法开始之前给出的量,取自于特定的对象集合——定义域 4)输出:一个算法产生一个或多个输出,这些输出是同输入有某种特定关系的量。5)有穷性/有限性:一个算法总是在执行了有穷步的运算之后终止。3.计算过程:只满足确定性、能行性、输入、输出四个特性但不一定能终止的一组规则。4.准确理解算法和计算过程的区别:不能终止的计算过程:操作系统;算法是“可以终止的计算过程”;算法的时效性:只能把在相当有穷步内终止的算法投入到计算机上运行。5.算法的语言主要有:自然语言,流程图,盒图,pad图,伪代码,计算机程序设计语言。 6.算法分类: 1)多项式时间算法:可用多项式(函数)对其计算时间限界的算法。常见的多项式限界函数有:ο(1)< ο(logn)< ο(n)< ο(nlogn)< ο(n2)< ο(n3)2)指数时间算法:计算时间用指数函数限界的算法。常见的指数时间限界函数:ο(2n)< ο(n!)< ο(nn)7.算法基本工具:循环与递归,算法与数据结构,优化算法的数学模型。8.主要算法:迭代算法,蛮力法,分治法,动态规划法,贪婪算法,图搜索基础。 二、算法的核心是思想 我们学习这门课不是仅仅掌握那几个经典算法例子,更重要的是为了学习蕴含在其中的思想方法。为什么呢?举个例子。有同学曾问我这样一个问题:1000只瓶子装满水,但有一瓶有毒,且毒发期为1个星期。现在用10只老鼠在一个星期内判断那只瓶子有毒,每只老鼠可以喝多个瓶子的水,每个瓶子可以只喝一点。问如何解决?其实一开始我也一头雾水,但是他提醒我跟计算机领域相关,我就立马有了思路,运用二进制。因为计算机的最基本思想就是二进制。所以说,我们不仅要学习算法,更得学习思想方法。 ①算法最基本的设计方法包括分治法,动态规划法,贪婪算法,周游法,回溯法,分支定界法。我们可利用分治法做快速排序,降低找n个元素中最大元和最小元的量级,降低n位二进制x和y相乘的量级,做strassen矩阵乘法等等。它的思想就是规模很大的问题分解为规模较小的独立的子问题,关键是子问题要与原问题同类,可以采取平衡法来提高性能。 动态规划法是把大问题分解为子问题,但是子问题是重复的,后面的问题可 以利用前面解决过的问题的结果。如构造最优二叉查找树,解决矩阵连乘时最小计算次数问题,寻找最长公共子序列等等。 贪婪算法就是局部最优法,先使局部最优,再依次构造出更大的局部直至整体。如kruscal最小生成树算法,求哈夫曼编码问题。 周游法就是简单理解就是采取一定的策略遍历图中所有的点,典型的应用就是图中的深度优先搜索(dfs)和广度优先搜索(bfs)。 回溯法就是就是在满足一定的条件后就往前走,当走到某步时,发现不满足条件就退回一步重新选择新的路线。典型的应用就是8皇后问题,平面点集的凸包问题和0-1背包问题。 分支定界法:它是解决整数规划问题一种最常用的方法。典型应用就是解决整数规划问题。 ②评价算法性能的方法如平摊分析中的聚集法,会计法和势能法。聚集法就是把指令分为几类,计算每一类的消耗,再全部叠加起来。会计法就是计算某个指令时提前将另一个指令的消耗也算进去,以后计算另一个指令时就不必再算了。势能法计算每一步的势的变化以及执行这步指令的消耗,再将每一步消耗全部累计。 这几种方法都是平摊分析法,平摊分析的实质就是总体考虑指令的消耗时间,尽管某些指令的消耗时间很大也可以忽略不计。上述三种方法难易程度差不多,每种方法都有属于它的难点。如聚集法中如何将指令有效分类,会计法中用什么指令提前计算什么指令的消耗,势能法中如何选取势能。因此掌握这些方法原理还不够,还要学会去应用,在具体的问题中去判断分析。 三、重点学习 1.贪婪算法 贪婪+其他算法:由于贪婪往往能大幅化简状态,利用问题的某些“单调性”,加上贪婪的思想,往往能是问题大幅简化,从而结合其他算法解决问题经典例题:田忌赛马,利用贪婪来确定状态。2.分治法 分而治之的思想在信息学竞赛中是非常重要的,下面主要介绍一下分治的经典应用 1)二分查找 思想很简单,功能很强大,边界要注意,负数要特判(noi2010 piano)在非负数范围内的二分一般写法 如果是l := mid1 或 +1则 mid :=(l + r + 1)div 2 2)快速幂 a^b =(a^(b div 2))^2 + ord(odd(b))*a取模也适用 3)快速排序,归并排序 任何一本算法书上都会讲的,这里就略过了,值得一提的是快排记得加上随机化 k := a[random(rg(x)*ans = 0 重构权,将f(i)-g(i)*ans作为新权值,用相应算法求出一个“最小值”,判断是否>=0,接着二分即可 5)树的分治 一般用来解决树上的路径或统计类问题,每次只考虑跟树根有关的信息,然后递归分治处理 树的分治通常有基于点或基于边的分治,基于点的难合,基于边的复杂度太高,这里只介绍基于点的分治 步骤:处理跟当前树根有关的信息,重新计算子树大小,在子树中选择重心为根,递归到相应子树处理。 因为每次选了重心,所以递归总共logn层,每层o(n)的复杂度,总复杂度就是o(nlogn)6)二分搜索 直接搜的复杂度是指数级的的话,一般是40左右的数据量,hash一半,搜一半,搜后面的时候利用之前的hash信息合并出原问题的解。 而直接搜的复杂度达到阶乘级的话n一般就不超过20了,做法一般差不多 经典例题:poi02szy,noi2001方程的解数。3.搜索 作为信息学竞赛中的所谓“万能算法”,搜索可以说是计算机学科所具有的最大特点了,自然地,搜索算法的应用自然也是非常之广泛,除了专门的搜索题,搜索一般可以用来部分预处理,打表找规律,当然还有骗分。 搜索的一般步骤:确定状态——选择搜索方式(dfs、bfs)——确定产生式规则——开始搜索。搜索的常见优化方式: 1)改变状态表示 这个需要根据题目而定,确定一个漂亮的状态表示,可能就有希望转向记忆化了,即使不行,搞出一个漂亮的状态表示是解决一道麻烦题的最重要的一步,再者,调试起来也会容易许多。 2)优化搜索顺序 这个优化在多数搜索中能起到摧枯拉朽的提速效果,通常我们选择枝叶较少的儿子先扩展,例如大名鼎鼎的dancing links,除了利用双向十字链表去除冗余状态,每次选择可扩展数最少的儿子扩展同样给它的神速创造了条件。3)可行性剪枝以及最优性剪枝 这是非常常用的剪枝思路之一,因题目而异,在迭代加深搜索中尤为重要 一般思路:考虑每次解最多变优多少,从当前的层数来看还有多少改进空间,如果已经不可能成为解或更新答案则可以剪枝了 ——a*及ida*算法:本质就是给搜索加上一个满足相容性的估价函数,然后用估价函数剪枝,理论上很牛b,实际上不常用,因为考场上很难想出满足那么多条件的估价函数,但记得一些常见模型的估价函数还是有价值的。例如15 数码的估价函数就可以选择除了0之外每个元素到自己该到的位置的曼哈顿距离之和,因为每次最多使一个数距离减少1,所以这个估价函数是相容的,再例如求k短路的a*算法就是用个堆维护 min{ f(s)+ g(s)}估价函数就是从汇点反搜的“反向最短路”的长度。 四、总结 在计算机软件专业中,算法分析与设计是一门非常重要的课程,很多人为它如痴如醉。很多问题的解决,程序的编写都要依赖它,在软件还是面向过程的阶段,就有程序=算法+数据结构这个公式。算法的学习对于培养一个人的逻辑思维能力是有极大帮助的,它可以培养我们养成思考分析问题,解决问题的能力。作为it行业学生,学习算法无疑会增强自己的竞争力,修炼自己的“内功”。 经过这门课的学习,我深刻的领悟到数学是一切算法分析与设计的基础。这门课的很多时间多花在了数学公式定理的引入和证明上。虽然很枯燥,但是有必不可少。我们可以清晰的看到好多算法思路是从这些公式定理中得出来的,尤其是算法性能的分析更是与数学息息相关。其中有几个定理令我印象深刻。 ①主定理 本门课中它主要应用在分治法性能分析上。例如:t(n)=a*t(n/b)+f(n),它可以看作一个大问题分解为a个子问题,其中子问题的规模为b。而f(n)可看作这些子问题的组合时的消耗。这些可以利用主定理的相关结论进行分析处理。当f(n)量级高于时,我们可以设法降低子问题组合时的消耗来提高性能。反之我们可以降低的消耗,即可以扩大问题的规模或者减小子问题的个数。因此主定理可以帮助我们清晰的分析出算法的性能以及如何进行有效的改进。 ②随机算法中的许多定理的运用 在这门课中,我学到了以前从未遇见过的随机算法,它给予我很大的启示。随机算法不随机,它可通过多次的尝试来降低它的错误率以至于可以忽略不计。这些都不是空穴来风,它是建立在严格的定理的证明上。如素数判定定理是个很明显的例子。它运用了包括费马小定理在内的各种定理。将这些定理进行有效的组合利用,才得出行之有效的素数判定的定理。尤其是对寻找证据数算法的改进的依据,也是建立在3个定理上。还有检查字符串是否匹配也是运用了许多定理:指纹的运用,理论出错率的计算,算法性能的评价也都是建立在数学定理的运用上。篇五:遗传算法学习心得 基本概念 遗传算法(genetic algorithms, ga)是一类借鉴生物界自然选择和自然遗传机制的随机化搜索算法。 它模拟自然选择和自然遗传过程中发生的繁殖、交叉和基因突变现象,在每次迭代中都保留一组候选解,并按某种指标从解群中选取较优的个体,利用遗传算子(选择、交叉和变异)对这些个体进行组合,产生新一代的候选解群,重复此过程,直到满足某种收敛指标为止。ga的组成:(1)编码(产生初始种群) (2)适应度函数 (3)遗传算子(选择、交叉、变异) (4)运行参数 编码 基因在一定能够意义上包含了它所代表的问题的解。基因的编码方式有很多,这也取决于要解决的问题本身。常见的编码方式有: (1)二进制编码,基因用0或1表示(常用于解决01背包问题)如:基因a:00100011010(代表一个个体的染色体)(2)互换编码(用于解决排序问题,如旅行商问题和调度问题) 如旅行商问题中,一串基因编码用来表示遍历的城市顺序,如:234517986,表示九个城市中,先经过城市2,再经过城市3,依此类推。 (3)树形编码(用于遗传规划中的演化编程或者表示) 如,问题:给定了很多组输入和输出。请你为这些输入输出选择一个函数,使得这个函数把每个输入尽可能近地映射为输出。 编码方法:基因就是树形结构中的一些函数。 (4)值编码(二进制编码不好用时,解决复杂的数值问题)在值编码中,每个基因就是一串取值。这些取值可以是与问题有关任何值:整数,实数,字符或者其他一些更复杂的东西。 适应度函数 遗传算法对一个个体(解)的好坏用适应度函数值来评价,适应度函数值越大,解的质量越好。适应度函数是遗传算法进化过程的驱动力,也是进行自然选择的唯一标准,它的设计应结合求解问题本身的要求而定。 如tsp问题,遍历各城市路径之和越小越好,这样可以用可能的最大路径长度减去实际经过的路径长度,作为该问题的适应度函数。 遗传算子——选择 遗传算法使用选择运算来实现对群体中的个体进行优胜劣汰操作:适应度高的个体被遗传到下一代群体中的概率大;适应度低的个体,被遗传到下一代群体中的概率小。选择操作的任务就是按某种方法从父代群体中选取一些个体,遗传到下一代群体。sga(基本遗传算法)中采用轮盘赌选择方法。 轮盘赌选择又称比例选择算子,基本思想:各个个体被选中的概率与其适应度函数值大小成正比。设群体大小为n,个体i 的适应度为 fi,则个体i 被选中遗传到下一代群体的概率为: 遗传算子——交叉 所谓交叉运算,是指对两个相互配对的染色体依据交叉概率按某种方式相互交换其部分基因,从而形成两个新的个体。交叉运算在ga中起关键作用,是产生新个体的主要方法。1.单交叉点法(用于二进制编码) 选择一个交叉点,子代在交叉点前面的基因从一个父代基因那里得到,后面的部分从另外一个父代基因那里得到。 如:交叉前: 00000|***00 11100|***01 交叉后: 00000|***01 11100|***00 2.双交叉点法(用于二进制编码) 选择两个交叉点,子代基因在两个交叉点间部分来自一个父代基因,其余部分来自于另外一个父代基因.如:交叉前: 01 |0010| 11 11 |0111| 01 交叉后: 11 |0010| 01 01 |0111| 11 3.基于“ 与/或 ”交叉法(用于二进制编码)对父代按位与”逻辑运算产生一子代a;按位”或”逻辑运算产生另一子代b。该交叉策略在解背包问题中效果较好.如:交叉前: 01001011 11011101 交叉后: 01001001 11011111 4.单交叉点法(用于互换编码) 选择一个交叉点,子代的从初始位置出发的部分从一个基因复制,然后在另一个基因中扫描,如果某个位点在子代中没有,就把它添加进去。 如:交叉前: 87213 | 09546 98356 | 71420 交叉后: 87213 | 95640 98356 | 72104 5.部分匹配交叉(pmx)法(用于互换编码) 先随机产生两个交叉点,定义这两点间的区域为匹配区域,并用交换两个父代的匹配区域。 父代a:872 | 130 | 9546 父代b:983 | 567 | 1420 变为: temp a: 872 | 567 | 9546 temp b: 983 | 130 | 1420 对于 temp a、temp b中匹配区域以外出现的数码重复,要依据匹配区域内的位置逐一进行替换。匹配关系:1<——>5 3<——>6 7<——>0 子代a:802 | 567 | 9143 子代b:986 | 130 | 5427 6.顺序交叉法(ox)(用于互换编码) 从父代a随机选一个编码子串,放到子代a的对应位置;子代a空余的位置从父代b中按b的顺序选取(与己有编码不重复)。同理可得子代b。父代a: 872 | 139 | 0546 父代b: 983 | 567 | 1420 交叉后: 子代a: 856 | 139 | 7420 子代b: 821 | 567 | 3904 7.循环交叉(cx)法(用于互换编码)cx同ox交叉都是从一个亲代中取一些城市,而其它城市来自另外一个亲代,但是二者不同之处在于:ox中来自第一个亲代的编码子串是随机产生的,而cx却不是,它是根据两个双亲相应位置的编码而确定的。 父代a:1 2 3 4 5 6 7 8 9 | | | | | 父代a:5 4 6 9 2 3 7 8 1 可得循环基因:1->5->2->4->9->1 用循环的基因构成子代a,顺序与父代a一样 1 2 4 5 9 用父代b剩余的基因填满子代a: 1 2 6 4 5 3 7 8 9 子代b的编码同理。(循环基因 5->1->9->4->2->5) 遗传算子——变异 变异是指依据变异概率将个体编码串中的某些基因值用其它基因值来替换,从而形成一个新的个体。ga中的变异运算是产生新个体的辅助方法,它决定了ga的局部搜索能力,同时保持种群的多样性。交叉运算和变异运算的相互配合,共同完成对搜索空间的全局搜索和局部搜索。 注:变异概率pm不能太小,这样降低全局搜索能力;也不能太大,pm > 0.5,这时ga退化为随机搜索。第四篇:算法总结
第五篇:算法学习心得