递归问题分析
递归函数定义
- 递归被用于定义数学函数或归纳证明
- 递归的数学模型分为基础和递归两部分
- 通过递归证明命题被称为数学归纳法,以正确的最小命题为基础,分为递归基础、递归假设、递归步骤三部分
汉诺塔问题
问题描述:将个从上到下大小依次递增的盘片将柱借助柱移到柱,其中不允许大盘片在小盘片上,求解移动次数
问题分析:将盘从柱移到柱,需先将盘通过柱移到柱,再将第盘片直接移到柱,然后将盘通过柱移到柱;若只剩一盘,则可直接移动
递归式:,即移动两次盘,一次直接移动
通项式:,可证明其是最优解
代码求解移动过程:
c++void RecursionSolution(int n, int from, int use, int to) { if (n == 1) { // from -> to directly cout << from << "->" << to << endl; return; } RecursionSolution(n - 1, from, to, use); cout << from << "->" << to << endl; RecursionSolution(n - 1, use, from, to); } int HanoiTower(int n) { RecursionSolution(n, 0, 1, 2); // 输出移动过程 return (1 << n) - 1; // 返回移动次数 }
直线划分平面问题
问题描述:用条直线划分一个平面,求出能划出的最多的部分数
问题分析:;时,每次使其和剩下条直线都有交点,则划分部分最多
递归式:
通项式:
证明其必定能做到上述操作:将次划分后的交点用圆围起来,用直径划分该圆,使交点平均地分布在圆的两部分(若交点数为奇数,则让穿过一点后再平均分配),则在划分的两个部分中,这些直线在圆外是不相交(交点在圆内)且不为同一直线(同一直线被划分在其两边),平移至圆外,则必定能交到个交点
推广:平面角划分平面问题
分析:使角始终处于上次划分后区域最大的部分,延长角的两条射线,则转换为条直线划分平面问题
递归式:
通项式:
圆划分平面问题:
每增加一个圆,新增圆与其余所有圆都相交且有两个交点,新增部分数目与新增交点数目相同,即:
因此
约瑟夫问题
问题描述:使编号依次递增(编号从开始)的人(共有人)按顺序围成一圈,每次报数后踢出该人,求幸存者的编号
问题分析:要知道,就需要先知道,但后者从开始,为了使前者能转换成后者,每次踢出后,需要找出其编号对应关系,若用表示下一轮报数从开始,则:
当时,可找到对应关系:
使括起的编号一一对应后,可找到如下关系:
其中为偏移量,减去即转换成编号从开始的情况,最后加上得到原问题从开始的情况
上述情况假设,实际上的情况下,踢出一人后报数从开始,因模运算的性质也满足上述递归式
递归式:,从开始编号
若要求从开始报数,可先求从开始报数,然后增加(注意模)
递归求解代码:
c++int Solution(int n, int m, int i) { // 从i开始编号, 从i开始报数 return n == 1 ? i : (Solution(n - 1, m, i) + m - i) % n + i; } int Josephus(int n, int m, int i, int j) { // 从i开始编号, 从j开始报数 return (Solution(n, m, i) - i) % n + j - i; }
及推广的通项式求解
上述过程实际只给出了递归式,实际上当时,原问题是以下问题的一个特例:
给出递归式,求出
清单法(猜证法):即给定可能的形式,通过给定特定的(要求能求出唯一对应的值),反过来推出中各系数的值
容易得到,如果递推式中含个变量,则至少需要找出个上述函数
当时,即所谓,可很容易地找到三个函数:
猜测
令,即
令,即
令,即
联立得,即
- 当时,正是
很不幸,无法给出如此多的函数来使用清单法求出一般形式的通解,但能根据递推式给出如下关系:
令,每右移一位相当于取中的,原本的末位则是:
因此对任何,将其写成进制,则等于
当限定为约瑟夫问题时,