《具体数学》1.1递归(一)

《具体数学》通过三个例子来讲递归,分别是:Hanoi Tower(汉诺塔)、Lines in the Plane(平行中的直线)、Josephus Circle(约瑟夫环问题)

这三个例子一直被数学家们反复研究;已知解法都使用递归,大问题化为小问题;都可以用计算机程序来求解;
我最近因为考试忙的其实也没看几页,就先把看的写出来吧;

1.1 汉诺塔

首先来看被称为“汉诺塔”(Hanoi Tower)的智力问题。该问题是法国数学家Edouard Lucas在1883年提出的。给定一个由八个大小不同的圆盘组成的塔,最初圆盘按尺寸递减的次序自底而上地堆放到三根杆中的一根上。类似的问题是婆罗门塔(64个盘子,一直挪到世界末日……,后面我们有相关的分析)

目标:把整个塔从一根杆移到另一根杆上。
规则:
(1)One time, one disk;
(2)No larger disks on smaller ones, Anytime.
直观上很难看出这个问题的解法,但是我们以前在C语言的递归部分已经遇到过,可以确信它有一个解.(结尾会给出c语言的代码片段)

书上写的解法其实已经很清楚了,目的是让我们求Tn是在Lucas规则下n个盘从一根杆移到另一根杆的最小移动次数,当n=1时显然T1=1,T2=3,这些都是小的问题,我们也可以通过小的问题去考虑大的,我们如何能转移一个大的塔?3个盘的实验表明要想获胜就是把顶上的2个移到中间,然后移第3个盘,再把另外的2个盘放上去,再扩展到n个盘一般移动的思路:首先把n-1个最小的盘转移到一个不同的杆(Tn-1次移动),然后移动最大的盘(一次移动),最后再把n-1个最小盘上的转移回最大的盘上(Tn-1次移动),所以,至多用2Tn-1+1次移动能转移n个盘(n>0)

Tn<=2Tn-1+1(n>0)

注意红色的部分,此公式用了‘<=‘而不是‘=‘,这本书真的是很严谨啊,因为我们的构造仅证明2Tn-1+1次移动是充分的,并未证明2Tn-1+1次移动是必要的。其实,没有很好的方法去证明它是必要的.在某个时刻我们一定要移动最大的盘,当我们移动最大盘时,n-1个最小的盘一定在一根杆上,且至少用Tn-1次移动把它们放到那里,我们假如不注意,则移动最大盘等等次数可能大于一次。但最后一次移动最大盘之后,我们一定要把n-1个最小盘转移回最大盘上,还要Tn-1次移动。因此Tn>=2Tn-1+1(n>0)

所以汉诺塔递归公式为:

T0=0

Tn=2Tn-1+1(n>0)

它给定一个边界值以及根据较早值表达一般值一个方程。我们有时把这个一般方程单独称为一个递归,但其实还是要一个边界值。

怎么去理解 递归呢,先去猜测一个正确的解,然后由这个解推出通解,找出规律,最后去证明规律的普遍性,数学归纳法是证明某个命题关于(对所有n>=n0)成立的一种一般方法,其实数学归纳法完美为递归作了准备。书上有一段是真的很重要的,在各种应用提出的许多问题中,汉诺塔的递归具有典型性,在找出像Tn那样表达式,我们经历三个阶段:

1:看看小的情形,这能使我们更深入的了解问题

2:求出和证明关心量的一个数学表达式,它使我们能就给定的量来计算任何n的Tn

3:求出和证明我们的数学表达式的一个闭形式

其实根据我们高中所学的知识,我们可以对Tn进行简化的:

T0+1=1;

Tn+1=2Tn-1+2,Un=2Un-1;

等比数列

汉诺塔C语言程序片段:#include <stdio.h>
int hanoiSolver(int peg1, int peg2, int peg3, int dCount)
{
   int mCount = 0;
   if (dCount > 1) {
       mCount += hanoiSolver(peg1, peg3, peg2, dCount - 1);
       printf("Move the top disk : peg %d -> peg %d\n", peg1, peg3);
       mCount += hanoiSolver(peg2, peg1, peg3, dCount - 1);
   } else {
       printf("Move the top disk : peg %d -> peg %d\n", peg1, peg3);
   }
   return ++mCount;
}
下一篇估计得有段时间去写了,天天考试,下一篇是打算写Lines in the Plane(平行中的直线)问题
总结:由于最近一直忙于复习考试,看的很少,但已经看完第一章了,课后习题还没写(感觉是在被教怎么做人了),真的写的很精彩,对于有些问题感到很神奇,对于很多解题思路很方法感觉还是有点吃力去理解,页边的涂鸦也很嗨啊,大师的公式推导,绝妙方法,真的让我醉了,醉的不行了,最后附上我在微博上看到的一句,我觉得很有道理:

算法和汇编,这才是计算机科学。低头制造垃圾简直暴殄天物。。。。。

《具体数学》1.1递归(一)

时间: 2024-11-02 02:51:59

《具体数学》1.1递归(一)的相关文章

具体数学 第一章 递归问题

1.河内塔问题 数学归纳法:①对最小规模时成立:②设对\(n=[1,k]\)时成立,证明对于\(n=k+1\)时也成立.于是问题对任意规模都成立. 它可以与递归的模型天然地结合在一起. 实际问题->递归式->数学归纳法->通项公式 通过处理递归式的某些项会使得数学归纳更加简单. 2.平面上的直线 展开递归式是求通项公式的好方法. 对于不易直接分析的实例,可以讨论"损失"了多少. 3.JOJO问题 对于一个递归式,把它的部分常量替换为未知数,希望求出它的通项公式中每个未

程序员的数学

第1章 0的故事——无即是有 本章学习内容 小学一年级的回忆 10进制计数法 什么是10进制计数法 分解2503 2进制计数法 什么是2进制计数法 分解1100 基数转换 计算机中为什么采用2进制计数法 按位计数法 什么是按位计数法 不使用按位计数法的罗马数字 指数法则 10的0次方是什么 10—1是什么 规则的扩展 对20进行思考 2—1是什么 0所起的作用 0的作用:占位 0的作用:统一标准,简化规则 日常生活中的0 人类的极限和构造的发现 重温历史进程 为了超越人类的极限 本章小结 第2章

【PHP】php 递归、效率和分析(转)

递归的定义 递归(http:/en.wikipedia.org/wiki/Recursive)是一种函数调用自身(直接或间接)的一种机制,这种强大的思想可以把某些复杂的概念变得极为简单.在计算机科学之外,尤其是在数学中,递归的概念屡见不鲜.例如:最常用于递归讲解的斐波那契数列便是一个极为典型的例子,而其他的例如阶层(n!)也可以转化为递归的定义(n! = n*(n-1)!).即使是在现实生活中,递归的思想也是随处可见:例如,由于学业问题你需要校长盖章,然而校长却说“只有教导主任盖章了我才会盖章”

数据结构(20)栈与递归

导言 递归 n阶Hanoi塔问题 算法 解析 汉诺塔3阶过程演示 导言 前面阶段用栈实现了表达式求值.括号匹配以及数字转换.这一次,我们介绍栈的另一个重要级别的应用-递归 递归 栈的重要应用是在程序设计语言中实现递归.一个直接调用自己或通过一系列的调用语句间接地调用自己的函数,称为递归函数. 递归是程序设计中强有力的工具. 递归是程序设计中一个强有力的工具.其一,很多数学函数是递归定义的,例如: 阶乘函数: Fact(n)={1      若n=1n ? Fact(n?1)     若n>0 2

递归之汉诺塔

递归的定义: 一个函数自己直接或间接调用自己(一个函数调用另外 一个函数和他调用自己是一模一样的,都是那三步, 只不过在人看来有点诡异.) 递归满足的三个条件: 1.递归必须得有一个明确的终止条件 2.该函数处理的数据规模必须在递减 3.这个转化必须是可解的. 循环和递归: 理论上循环能解决的,肯定可以转化为递归,但是这个 过程是复杂的数学转化过程,递归能解决不一定能转化 为循环,我们初学者只要把经典的递归算法看懂就行, 至于有没有能力运用看个人. 递归: 易于理解 速度慢 存储空间大 循环 不

递归该怎么写(一)

递归定义 递归:无限调用自身这个函数,每次调用总会改动一个关键变量,直到这个关键变量达到边界的时候,不再调用. 我们现在开始来举例子,然后总结如何写好递归程序.(这种针对可以找出数学表达式的递归程序,对于写不出数学表达式的或者不好找的会在之后的博客中补充) 例子1: n的阶乘. 我们先来写出数学表达式 代码部分: 1 __author__ = "WSX" 2 3 def f(n): 4 if n == 1: 5 return 1 6 else: 7 return f(n-1) * n

数据-第19课-递归的应用实战一

第19课-递归的应用实战一 1. 递归的数学思想 (1)      递归是一种数学上分而自治的思想. (2)      递归将大型复杂问题转化为与原问题相同但规模较小的问题进行处理. (3)      递归需要有边界条件. l  当边界条件不满足时,递归继续进行. l  当边界条件满足时,递归停止. 2 . 递归的数学表示 n > 1 n==1 (1)斐波拉契数列递归解法 #include <stdio.h> int fibonacci(int n) { if( n > 1 ) {

【算法】还在用递归实现斐波那契数组,面试官一定会鄙视你到死

我记得在初学C语言的时候,大学老师经常会讲一些常见的数学问题及递归的使用,其中斐波那契数组的实现就是一定会被拿出来举例的.在后来工作中,面试做面试题的时候,也很大概率会出现编程实现斐波那契额数组算法.可以说,在我们编程道路上,编写程序实现斐波那契数组算法是每个程序员必定会做的一件事. 斐波那契数列指的是这样一个数列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,

还在用递归实现斐波那契数列,面试官一定会鄙视你到死

斐波那契数列指的是这样一个数列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368...... 我记得在初学C语言的时候,大学老师经常会讲一些常见的数学问题及递归的使用,其中斐波那契数列就是一定会被拿出来举例的.在后来工作中,面试做面试题的时候,也很大概率会出现编写算法实现斐波那契额数列求值.可以说,在我们编程道路上,编写算法实现斐波那契数列是

Haskell函数的语法

本章讲的就是 Haskell 那套独特的语法结构,先从模式匹配开始.模式匹配通过检查数据的特定结构来检查其是否匹配,并按模式从中取得数据. 在定义函数时,你可以为不同的模式分别定义函数本身,这就让代码更加简洁易读.你可以匹配一切数据类型 --- 数字,字符,List,元组,等等.我们弄个简单函数,让它检查我们传给它的数字是不是 7. lucky :: (Integral a) => a -> String   lucky 7 = "LUCKY NUMBER SEVEN!"