算法就是能够证明正确的解题步骤,算法有许多种,最简单的无非下面的六种:递推法、贪心法、列举法、递归法、分治法和模拟法。下面举例说明。
什么是递推法
递推法这种解题方法其实在我们编程的过程中用的很多,只不过没有将其上升到理论的高度罢了。所谓递推法,就是找出和时间先后相联系或和数的大小相联系的步骤,上一步和下一步和数字的增大或减小有一定的联系。我们要么从前向后(或从小到大)推导,也可从后向前(或从大到小)推导。由此得出两种推导方法:顺推法和倒推法。请看下面的示例。
示例:猴子分食桃子
五只猴子采得一堆桃子,猴子彼此约定隔天早起后再分食。不过,就在半夜里,一只猴子偷偷起来,把桃子均分成五堆后,发现还多一个,它吃掉这桃子,并拿走了其中一堆。第二只猴子醒来,又把桃子均分成五堆后,还是多了一个,它也吃掉这个桃子,并拿走了其中一堆。第三只,第四只,第五只猴子都依次如此分食桃子。那么桃子数最少应该有几个呢?
编程简析
怎样编程呢?先要找一下第N只猴子和其面前桃子数的关系。如果从第1只开始往第5只找,不好找,但如果思路一变,从第N到第1去,可得出下面的推导式:
第N只猴 第N只猴前桃子数目
5 s5=x
4 s4=s5*5/4+1
3 s3=s4*5/4+1
2 s2=s3*5/4+1
1 s1=s2*5/4+1
s1即为所求。上面的规律中只要将s1-s5的下标去掉:
s=x
s=s*5/4+1
s=s*5/4+1
s=s*5/4+1
s=s*5/4+1
所以可以用循环语句加以解决。
综观程序的整体结构,最外是一个循环,因为循环次数不定,可以使用While循环,其结束条件则是找到第一个符合条件的数。为了做出上面while循环的结束条件,还需进一步分析上述规律的特点,要符合题目中的要求,s1-s4四个数必须全部为整数,这个可作为条件。
小结
上面应用的推导方法就是倒推法。生活中的更多问题采用顺推法就可得到,也即从1-N,但不论倒推还是顺推,能递推出并解出问题是我们的本意。
什么是贪心法
贪心法就是做一种目前最贪婪的行动,一步步解决问题。贪心法和递推法有相似之外,也是从问题的某一个初始解出发,向给定的目标递推,但不同的是每一步不是依据某一个固定的递推式,而是做一个当时看似最佳的贪心选择,不断地将问题归结为更小的相似的问题。
示例:删数问题
链盘输入一个高精度的数N,去掉任意S个数字后剩下的数字按原左右次序组成一个新的正整数,编程对于给定的N和S,寻找一种方案使得剩下的数字组成的新数最小。
为了便于操作,将N做为字符串的形式输入,可以使用尽可能逼近目标的贪心算法来完成,删数的过程中是一个一个进行删除的,为了保证最后得到的数最小,每一步总是要删除使剩下的数最小的数字。之所以做出这样贪心的选择,是因为删S个数字的最优解,包含了删除一个数字的子问题的最优解。
为了实现上述目的,我们可以进行S次选择,每次都选择N中最大的数字,此数字选择后将不再参与下次的选择。
小结
这就是有趣的贪心算法,说是贪得无厌可以,说是守住当前的既得利益,以此为基础,再稳扎稳打地进行下一步也行!
什么是列举法
列举是针对问题所有的可能一一查看是不是符合条件,有些“宁肯错杀一千,不可放过一个”的作风。下面的老题最能说明这种情况。
示例:百钱买百鸡
公鸡3元每只,母鸡5元每只,小鸡1元3只,一百元钱买一百只鸡。请求出公鸡,母鸡和小鸡的数目。
编程简析
我们做最极端的假设,公鸡可能是0-100,母鸡也可能是0-100,小鸡还可能是0-100,将这三种情况用循环套起来,那就是1000000种情况。这就是列举法。为了将题目再简化一下,我们还可以对上述题目进行一下优化处理:
假设公鸡数为x,母鸡数为y,则小鸡数是100-x-y,也就有了下面的方程式:
3*x+5*y+(100-x-y)/3=100
从这个方程式中,我们不难看出大体的情况:公鸡最多有33只,最少是没有,即x的范围是0-33;母鸡最多20只,最少0只,即母鸡的范围是0-20;有了公鸡母鸡,小鸡数自然就是100-x-y只。可能的方案一共有34*21种,在这么多的方案中,可能有一种或几种正好符合相等的条件。
电脑怎样工作呢?计算机事实上就是将上述34*21种方案全部过滤一遍,找出符合百钱买百鸡条件的(也即上式),只要符合,这就是我们要的输出结果。
小结
这就是列举法,将可能的情况一网打尽;不过在应用过程中,我们最好还是做些优化,不然,要浪费好多没必要浪费的时间。
什么是递归
说白了递归就象我们讲的那个故事:山上有座庙,庙里有个老和尚,老和尚在讲故事,它讲的故事是:山上有座庙,庙里有个老和尚,老和尚在讲故事,它讲的故事是:……也就是直接或间接地调用了其自身。
就象上面的故事那样,故事中包含了故事本身。因为对自身进行调用,所以需对程序段进行包装,也就出现了函数。
函数的利用是对数学上函数定义的推广,函数的正确运用有利于简化程序,也能使某些问题得到迅速实现。对于代码中功能性较强的、重复执行的或经常要用到的部分,将其功能加以集成,通过一个名称和相应的参数来完成,这就是函数或子程序,使用时只需对其名字进行简单调用就能来完成特定功能。
函数又可分为自定义的和系统附带的,但不管是自定义的还是系统的,他们都对相应的功能进行了封装,以利于我们经常性地使用。例如我们的对一个小数取整数INT()函数,不论什么样的小数,往()中一放,将来得到的值就自动将小数去除了。函数执行完将返回一个值,当然这个值可以是各种类型的,子程序仅仅执行一个过程,不返回数值。
函数和子程序是执行递归的干将。
示例:小猴吃枣
小猴第一天摘下若干枣子,当即吃掉了一半,不过瘾又多吃了一个;第二天吃了剩下的一半又多吃了一个;以后每一天都吃了前一天剩下的一半多一个。到第十天小猴再想吃时,见到只剩下一只枣子了。问第一天这堆枣子有多少?
从上题中我们可看到一个令人欣喜的规律,第十天为1,第九到第一天中后一天与1的和的两倍与前一天相等。
小结
函数和子程序是程序瘦身计划的一部分,通过它们可以使程序中的代码适当减肥,长度维持在一个更合理的位置。这种作用和循环的瘦身作用一起,使一个执行很长的代码可以变得很简洁。这也更适合我们利用计算机作为工具的目的:人类做尽量少的工作,计算机仍能解决原先的问题。
另一个奇妙之处是:他们创造了递归!
什么是分治法
为了解决一个问题,算法有时需不止一次地对自身进行调用,来解决相类似的子问题。这样的算法通常称为分治法:将原问题分成n个规模较小而结构与原问题相似的子问题。下面通过排序的一种方法来看一下。
希尔排序即是采用分治法来进行排序的,又称做缩小增量排序,其思想是:把已经在数组中的数据按下标的一定增量分组,对分出的每一小组使用插入排序,随着增量逐渐减小,所分成的组包含的数据越来越多,直到减小到1时,整个数据合并成一组,构成一组有序数,则完成排序。
示例:十个数,从大到小排序。
数据放在一个数组a(10)中,假如原始数据如下:70. 53. 57. 28. 30. 77. 1. 76. 81. 70,则排序过程如下:
增量值
5: 77. 53. 76. 81. 70. 70. 1. 57. 28. 30.
2: 77. 81. 76. 70. 70. 57. 28. 53. 1. 30.
1: 81. 77. 76. 70. 70. 57. 53. 30. 28. 1.
其中上面三个增量值对应的都是以该增量完成本轮排序后的情况,看增量为5时要和原始数据比较,增量为2的情况要和5比较,1要和2比较,这样其中的规律就清楚了。
小结
在进行希尔排序时,需注意增量序列的取值方法,并且使这些序列中的值没有除1之外的公因子,且最后一个增量值必须为1。
能解决问题的办法都是好办法,问题不一定整体解决才好。这就是分治的思想。
随机函数的出现
通过语言编程一般来说对事物的认识是很确定的了,是一就是一,是二就是二,还有一个问题,有一些不那么确定的事情该如何处理,象我们的彩票抽奖,如果是确定的了,那也就不用抽了,恐怕也就没人玩了。
对于这一类的事情,该怎么办呢?语言中为我们提供了随机函数,也就是说通过它得到的一个值将是不能确定的。
随机函数产生的秘密
计算机常常需要模拟随机选择的数目,有多种不同的方法可以产生具有随机性质的数,由于通过此种系统的方法产生的不是真正的随机数,所以一般称做伪随机数。最常用的产生伪随机数的方法称为线性同余法。公式如下,选择四个数:模数m,乘数a,增量c和种数x0,使 2≤a<m, 0≤c<m, 0≤x0<m,可以生成一个伪随机序列{xn},使得对于所有的n,0≤x0<m。生成的办法是逐次同余:
xn+1=(axn+c)mod m
应用和变通
随机函数有一个范围,即Rnd 函数返回小于 1 但大于或等于 0 的小数值。但通常我们要解的问题不在这个范围内,如何解决呢?
示例:最简单的抽奖程序,做一个猜1-100之间数的游戏。
因为随机函数的范围是一个0-1之间的小数,和题目要求的范围相差很大。所以,当我们用到的值不在这个范围之内时,我们可以想点变通的办法。要想做到从1-100之间进行取数,必须扩大100倍才行。不难计算RND*100的范围却不是1-100,而是0-100,不包括0和100,怎样就是1-100了呢?加上一就有了,范围成了1-101,不包括1和101,只要对得到的数只取整数,这个数只要这样表达就出来了。
小结
随机函数是程序设计中一道亮丽的风景。这个函数是非常有用的,她可能是计算机语言中唯一没有理性的东东了。就好象我们人类所具有的现省心的想法,妙手偶得之的佳句。正因为这个唯一性,也就不难看出她在计算机语言中的地位了。
分享到:
相关推荐
《深入浅出算法竞赛》是一本旨在帮助读者深入理解算法竞赛的书籍,通过简洁明了的语言和具体的实例,介绍了算法竞赛的核心知识点和常用算法,同时也强调了算法的实际应用和优化方法。该书籍可以帮助读者更好地理解和...
《Scratch编程入门与算法进阶》是一本面向青少年和初学者的Scratch编程和算法教育书籍,本书以图文并茂的方式,系统地介绍了Scratch编程的基础知识和常用算法,旨在帮助读者深入理解计算机编程的基本概念和思想,...
哈希表是一种常用的数据结构,用于高效地存储和检索数据。本章讲解了哈希表的基本原理、哈希函数的设计以及冲突解决策略等。 ### 第15章:动态规划 动态规划是一种强大的算法设计技术,用于解决具有重叠子问题和最...
分治策略是一种常用的算法设计策略,它将问题划分为若干个子问题,然后递归地解决这些子问题。最后将子问题的解合并,得到原问题的解。 贪心算法是一种在每一步选择中都采取当前最优的选择,从而希望导致结果是全局...
在入门篇中,本书首先介绍了算法竞赛的基础知识,包括竞赛的规则、评分标准、常用算法和数据结构等。这一部分还详细地介绍了一些基础的算法设计和优化技巧,如贪心、分治、动态规划等。这些基础知识是算法竞赛的基础...
递归是算法设计中常用的技术,主定理(Master Theorem)则是一种解决特定递归关系的方法。 7. 概率分析和随机算法。这些章节将涵盖概率分析在算法设计中的应用,以及随机算法的概念和实现。 8. 排序算法和堆排序。...
【标题】:“十大算法.pdf”概述了数学建模竞赛中常用的十类算法,包括蒙特卡罗算法、数据处理算法、规划类算法、图论算法、动态规划等计算机算法、最优化理论的非经典算法、网格算法和穷举法、离散化方法、数值分析...
- **循环控制结构:** 文档中的`while`循环用于控制查找单词的逻辑,这是算法中常用的控制结构,用于执行重复任务直到满足特定条件。 - **字符串查找算法的实现:** 通过上述步骤,文档展示了一个基本的字符串查找...
2. 常用算法模板:包括排序算法(如快速排序、归并排序)、搜索算法(如二分查找、深度优先搜索、广度优先搜索)、动态规划、贪心算法、回溯法、分治算法等。 3. 数学模板:包含数学运算的基本函数,如最大公约数、...
6. **哈希表**:一种通过哈希函数来快速访问数据的结构,常用以实现关联数组、数据库索引等。 #### 算法分析基础 1. **时间复杂度和空间复杂度**:衡量算法性能的两个重要指标,通常用大O表示法来描述算法的渐进...
以上知识点均来自于给定文件内容的描述和部分内容的摘录,涵盖了自我介绍、项目介绍、行业观点、学习方法、职业规划、函数柯里化、对象创建、面向对象编程概念、类的声明、方法的调用及继承等方面。在面试准备中,...
__C_____是最常用的一类访问控制机制,用来决定一个用户是否有权访问一些特定客体的一种访问约束机制。 A、强制访问控制 B、访问控制列表 C、自主访问控制 D、访问控制矩阵 SYN风暴属于___A____攻击。 A、拒绝...
鹫尾泰治谈到了计算机科学的本质,他认为,计算机科学是一种解决问题的科学,它包括计算机体系结构、操作系统、编译原理、网络技术、人工智能等多个领域。掌握这些领域的知识对于成为一个优秀的程序员是至关重要的。...
这是一种在组合优化问题中常用的算法,能够找到最优的元素匹配方式,对于图片拼接来说,该算法可以有效地确定碎片间的相对位置。 4. 间距判断算法和分行算法:间距判断算法用于筛选出碎片中最左侧的列,而分行算法...
机器人的运动可以通过多种方式表示,其中欧拉角是一种常用的描述旋转的方法。欧拉角能够将三维空间中的旋转分解为沿三个正交坐标轴的序列旋转,即所谓的“绕X轴旋转”、“绕Y轴旋转”和“绕Z轴旋转”。本文档详细地...
VB一些常用控件集,以及一些方法模块,编辑框.ctl、进度条、全局热键钩子、网站服务器、托盘控件、WinSock.ctl、曲线图.ctl、压缩算法-升级版.cls、数组加解密.cls、打开文件属性面板.bas等,其中一个模块的部分代码...
此外,他还讨论了递归和分治策略,这些都是解决复杂问题的常用方法。 第二卷《排序与查找》则进一步深入研究了排序和查找算法的细节,包括各种内部排序(如快速排序、归并排序)和外部排序,以及各种查找数据结构...
标题中的"SVM_som"可能指的是SVM与自组织映射网络(Self-Organizing Map, SOM)的结合应用,而"SMO"则代表了SVM的一种优化算法——Sequential Minimal Optimization。 SVM的核心思想是找到一个超平面,使得两类样本...
6. 高斯滤波处理:代码中提到了`CV_GAUSSIAN`滤波器,它是一种平滑图像的常用方法,可以减少图像噪声,增强图像的整体质量。 7. 动态内存管理:摘录提到了内存块的创建和销毁,使用`cvCreateMemStorage`和`...