2011-程序设计-12-函数-4-递归与回溯

合集下载

递归与回溯算法专题

递归与回溯算法专题

递归算法适用的一般场合为:
① 数据的定义形式按递归定义。 如裴波那契数列的定义:
1n 0
fn
2n 1
f n1 f n2 n 2
对应的递归程序为
function fib(n: Integer): Integer;
begin
if n = 0 then
fib := 1
{递归边界}
else if n = 1 then
用过程式move(n-1,a,b,c); 3. 将a柱上剩下的一片直接移到C柱上; 4. 用a柱作为协助过渡,将b柱上的(n-1)片移到c柱上,调
用过程move(n-1,b,c,a);
源程序见附件
新汉诺(hanoi)塔问题
设有n各大小不等的中空圆盘,按从小到大的顺序从1到n编号。将这n个圆盘 任意的迭套在三根立柱上,立柱的编号分别为A、B、C,这个状态称之为初始 状态。问题要求找到一种步数最少的移动方案,使得从初始状态转变为目标 状态。移动时有如下要求:
递归有如下特点:
①它直接或间接的调用了自己。
②一定要有递归终止的条件,这个条件通常称为边界条件。
与递推一样,每一个递推都有其边界条件。但不同的是,递推是由边界条 件出发,通过递推式求f(n)的值,从边界到求解的全过程十分清楚;而递 归则是从函数自身出发来达到边界条件,在通过边界条件的递归调用过程 中,系统用堆栈把每次调用的中间结果(局部变量和返回地址)保存起来, 直至求出递归边界值f(0)=a。然后返回调用函数。返回的过程中,中间结 果 相 继 出 栈 恢 复 , f(1)=g(1,a)f(2)=g(2,f(1))…… 直 至 求 出 f(n)=g(n,f(n-1))。
fib := 2
{递归边界}

递归与回溯法

递归与回溯法

7
template<class type> void perm(type list[], int k, int m) 1 { if (k==m) //输出一个排列 else 4 for (int i=k ; i<=m; i++) 5 { swap(list[k], list[i]); 6 perm(list, k+1, m); 7 swap(list[k], list[i]);} 9 }
本例中的Ackerman函数却无法找到非递归的定义。
4
例4
排列问题
设计一个递归算法生成n个元素{r1,r2,…,rn}的全排列。 设R={r1,r2,…,rn}是要进行排列的n个元素,Ri=R-{ri}。
集合X中元素的全排列记为perm(X)。
(ri)perm(X)表示在全排列perm(X)的每一个排列前加上前缀得 到的排列。R的全排列可归纳定义如下:
eg: list[]={1, 2, 3, 4}
k
//输出一个排列
else for (int i=k ; i<=m; i++) { swap(list[k], list[i]); perm(list, k+1, m); swap(list[k], list[i]); }
输出结果:
1234 1243
1324
x (x ) n m 2 x x( x )
n m 2
10
例6:n阶Hanoi塔问题:
11
void hanoi(int n, int a, int b, int c) { 设M(n)为移动盘子的次数,对于M(n)有下 if (n > 0) 列递推等式: { 当n>1时, hanoi(n-1, a, c, b); M(n)= M(n-1)+1+ M(n-1)=2 M(n-1)+1 move(a,b); hanoi(n-1, b, a, c); 当=1时, M(n)=1 } } 我们来解这个递推公式; M(n)= 2 M(n-1)+1 =2[2M(n-2)+1]+1= 22 M(n-2)+2+1 = 22 [2M(n-3)+1]+2+1=23 M(n-3)+ 22 +2+1=… = 2i M(n-i)+ 2i-1 + 2i-2 +…+2+1=2i M(n-i))+ 2i-1=… = 2n-1 M(n-(n-1))+ 2n-1-1= 2n -1

递归的回溯法 非递归的回溯法

递归的回溯法 非递归的回溯法

递归的回溯法和非递归的回溯法都是解决问题的一种算法思想,它们在不同的问题领域有着广泛的应用。

本文将就递归的回溯法和非递归的回溯法的概念、原理、特点和应用进行详细的介绍,以期能对读者们有所启发和帮助。

一、递归的回溯法递归的回溯法是一种通过递归的方式对问题进行搜索和求解的算法思想。

在递归的回溯法中,我们首先尝试解决问题的一个小部分,然后递归地解决剩余部分,最终将所有的部分组合起来得到问题的解。

具体来说,递归的回溯法通常包括以下几个步骤:1. 选择合适的参数和返回值。

在使用递归的回溯法时,我们需要确定递归函数的参数和返回值,以便正确地传递信息和获取结果。

2. 递归地调用自身。

在递归的回溯法中,我们需要将问题拆分为一个或多个小问题,并通过递归地调用自身来解决这些小问题。

3. 设定递归的结束条件。

在递归的回溯法中,我们需要设定递归的结束条件,以防止递归无限循环。

4. 处理递归的结果。

在递归的回溯法中,我们需要将递归的结果合并或处理,得到最终的问题解决方案。

递归的回溯法在许多领域都有着广泛的应用,比如在图论、搜索、排列组合等领域。

它具有简洁高效的特点,可以帮助我们快速地解决一些复杂的问题。

二、非递归的回溯法非递归的回溯法与递归的回溯法相比,它采用了循环的方式对问题进行搜索和求解。

在非递归的回溯法中,我们通常使用栈来存储状态信息,通过循环不断地弹出和压入状态,直到找到问题的解。

非递归的回溯法通常包括以下几个步骤:1. 初始化状态信息。

在使用非递归的回溯法时,我们需要初始化一些状态信息,比如初始位置、初始值等。

2. 使用栈来存储状态。

在非递归的回溯法中,我们通常使用栈来存储状态信息,通过不断地弹出和压入状态来搜索问题的解。

3. 循环搜索解决方案。

在非递归的回溯法中,我们通过循环不断地弹出和压入状态,直到找到问题的解。

4. 处理结果。

在非递归的回溯法中,我们需要将搜索得到的结果进行处理,得到最终的问题解决方案。

非递归的回溯法在一些特定的问题领域,比如迷宫求解、八皇后问题等有着较好的应用效果。

C语言与程序设计ppt-第12章递归

C语言与程序设计ppt-第12章递归

第12章 递 归
华中科技大学计算机学院 卢萍
华中科技大学计算机学院C语言课
2021/4/25
程组
1
本章讲授内容
递归(recursion)是一项非常重要的编 程技巧,可以使程序变得简洁和清晰,是 许多复杂算法的基础。本章介绍 递归、递归函数的概念; 递归的执行过程; 典型问题的递归函数设计; 分治法与快速排序; 回溯法; 递归在动态规划等算法中的应用。
12
【例12.3】 设计一个求解汉诺塔问题的算法。
这是一个典型的用递归方法求解的问题。要移动n个 盘子,可先考虑如何移动n 1个盘子。分解为以下3 个步骤:
(1)把A上的n-1个盘子借助C移到B。 (2)把A上剩下的盘子(即最大的那个)移到C。 (3)把B上的n-1个盘子借助A移到C。 其中,第(1)步和第(3)步又可用同样的3步继
2021/4/25
华中科技大学计算机学院C语言课程组
2
12.1 递归概述
递归是一种函数在其定义中直接或间接调用 自己的编程技巧。递归策略只需少量代码就 可描述出解题过程所需要的多次重复计算, 十分简单且易于理解。
递归调用:函数直接调用自己或通过另一函 数间接调用自己的函数调用方式
递归函数:在函数定义中含有递归调用的函 数
续分解,依次分解下去,盘子数目n每次减少1,直 至n为1结束。这显然是一个递归过程,递归结束条 件是n为1。
2021/4/25
华中科技大学计算机学院C语言课程组
13
函数move(n,a,b,c)
为了更清楚地描述算法,可以定义一个函数 move(n,a,b,c)。该函数的功能是:将n个盘 子从木桩a上借助木桩b移动到木桩c上。算法 的第(1)步和第(3)步的实现都是递归调 用,分别为move(n-1,a,c,b)和move(n1,b,a,c)。

递归算法步骤 -回复

递归算法步骤 -回复

递归算法步骤-回复递归算法步骤指的是一种通过自身调用来解决问题的算法。

在递归算法中,问题会被分解成更小的子问题,直到达到基本情况,然后再逐步返回解决方案。

本文将详细介绍递归算法的步骤,重点探讨递归的定义、分析、实现和调试技巧。

第一步:定义递归递归算法的关键在于将一个大型问题分解为小型的相似问题来解决。

为了使用递归解决问题,首先需要定义递归函数。

递归函数应包含以下要素:1. 基本情况(Base case):即递归的结束条件。

每个递归问题必须有一个终止点,否则递归将无法结束。

2. 递归调用(Recursive call):即函数自身调用。

在递归步骤中,函数会调用自身来解决同一问题的较小版本。

第二步:分析问题在使用递归算法解决问题之前,需要仔细分析问题的特征和结构。

了解问题的特点对于递归的实现至关重要。

分析问题包括以下几个方面:1. 确定可行性:确定问题是否适合用递归解决。

某些问题可能需要其他算法才能更有效地解决。

2. 确定子问题和终止条件:确定如何将问题分解为较小的子问题,并确定如何确定基本情况,即递归的终止条件。

第三步:实现递归一旦了解了问题的特点,就可以开始实现递归算法。

递归算法的实现通常包含以下几个步骤:1. 处理基本情况:在递归函数中,首先应该处理递归的终止条件,即基本情况。

这可以是函数返回一个已知值,或者其他适当的操作。

2. 处理递归调用:之后,处理递归调用步骤。

在递归函数内部,将问题分解为较小的子问题,并调用自身来处理这些子问题。

将子问题的结果进行合适的组合,将成为整个问题的解。

3. 返回结果:最后,将结果返回给上一层递归函数。

在递归过程中,每一层递归都会将结果传递给上一层,直到达到最外层递归调用。

第四步:调试递归递归算法的调试可以是一项具有挑战性的任务,因为它涉及到多层次的函数调用。

以下是一些调试递归算法时的技巧:1. 打印调试信息:在递归函数中,可以使用打印语句来输出关键变量的值,以帮助跟踪递归的执行过程。

递归与回溯

递归与回溯

procedure run(当前状态); var i:integer; begin if 当前状态为边界 then begin if 当前状态为最佳目标状态 then 记下最优结果; exit;{回溯} end; for i←算符最小值 to 算符最大值 do begin 算符i作用于当前状态,扩展出一个子状态; if (子状态满足约束条件)and(子状态满足最优性要求)then run(子状态) end; end;
递归的概念与应用
递归过程是借助于一个递归工作栈来实现的 问题向一极推进,这一过程叫做递推; 问题向一极推进,这一过程叫做递推; 问题逐一解决,最后回到原问题, 问题逐一解决,最后回到原问题,这一过程 叫做回归。 叫做回归。 递归的过程正是由递推和回归两个过程组 成。
递归的概念与应用
用递归方法编写的问题解决程序具有结构清晰, 用递归方法编写的问题解决程序具有结构清晰,可 读性强等优点, 读性强等优点,且递归算法的设计比非递归算法的 设计往往要容易一些, 设计往往要容易一些,所以当问题本身是递归定义 或者问题所涉及到的数据结构是递归定义的, 的,或者问题所涉及到的数据结构是递归定义的, 或者是问题的解决方法是递归形式的时候, 或者是问题的解决方法是递归形式的时候,往往采 用递归算法来解决。 用递归算法来解决。
输出 180 12
算法分析
本题可以用递归求解:设当前有N个物品 容量为M; 个物品, 本题可以用递归求解:设当前有 个物品,容量为 ;因 为这些物品要么选,要么不选, 为这些物品要么选,要么不选,我们假设选的第一个物品 编号为I( 号物品不选), 问题又可以转化为有N-I 编号为 ( 1~I-1号物品不选), 问题又可以转化为有 号物品不选 ),问题又可以转化为有 个 物 品 ( 即 第 I+1~N 号 物 品 ) , 容 量 为 M-Wi 的 子 问 如此反复下去, 题……如此反复下去,然后在所有可行解中选一个效益最 如此反复下去 大的便可。 大的便可。 另外,为了优化程序,我们定义一个函数如下: 另外,为了优化程序,我们定义一个函数如下: F[I]表示选第 表示选第I~N个物品能得到的总效益。不难推出: 个物品能得到的总效益。 表示选第 个物品能得到的总效益 不难推出: F[N]=Pn F[I]=F[I+1]+Pi (I=1…N-1) ) 假设当前已选到第I号物品,如果当前搜索的效益值 +F[I+1]的值仍然比当前的最优值小,则没有必要继续搜 的值仍然比当前的最优值小, 的值仍然比当前的最优值小 索下去。 索下去。

递归和回溯

递归和回溯

递归和回溯递归和回溯是计算机科学中重要的概念,它们被广泛地应用在算法和程序设计中。

递归(Recursion)是指一种程序设计技术,它将问题的解决方法分解为更小的子问题,依次解决子问题,最后将各个子问题的解合并起来得到问题的解。

而回溯(Backtracking)则是指一种试探性的搜索算法。

回溯算法通过递归依次试探问题的每一种可能解决办法,对于无解或者不符合要求的情况进行回溯,寻找新的解决方案。

本文将从定义、应用、优化三方面详细讲解递归和回溯算法。

一、递归的定义及应用1.1 递归的概念递归是一种程序设计技巧,它将一个问题分解为更小的子问题,问题的解决方法与子问题的解决方法相同,通过递归调用子问题的解决方法,最终得到问题的解决方法。

递归有两个必要条件:一是递归终止条件(递归出口);二是递归调用(自调用)。

综上所述,递归程序必须具备的特点是具有递归出口和自调用两个基本属性。

1.2 递归的应用递归在程序设计中的应用非常广泛,常见的应用包括:树结构遍历、排序、搜索、字符串处理、图的深度优先搜索等等。

递归应用最为广泛的领域是算法和操作系统。

在算法领域中,递归是解决分治、动态规划等问题的主要思想,如快速排序、归并排序和斐波那契数列等都是基于递归设计的。

在操作系统中,递归的应用也比较广泛,比如UNIX系统中使用递归算法实现打印目录下所有文件的函数,Windows系统中使用递归算法查询注册表等。

1.3 实例分析:斐波那契数列斐波那契数列是指:1、1、2、3、5、8、13、21、34、……。

其中第1项和第2项为1,从第3项开始,每一项为前两项的和。

斐波那契数列可以用递归方式写出如下代码:```c++ int fib(int n) { if (n <= 2){ return 1; } return fib(n - 1) + fib(n - 2); } ```该递归函数表示了斐波那契数列的定义,在递归函数中,首先判断n是否小于等于2,如果是,直接返回1;如果不是,继续递归调用fib(n-1)和fib(n-2),最后将两个递归函数的返回结果相加作为函数的返回结果。

C语言高级特性递归与回溯算法

C语言高级特性递归与回溯算法

C语言高级特性递归与回溯算法C语言高级特性:递归与回溯算法递归和回溯算法是C语言中一种非常重要的高级特性,它们在解决一些复杂问题和优化代码时发挥着关键的作用。

本文将会介绍递归和回溯算法的原理和应用,并通过具体的示例来说明它们的使用方法。

一、递归算法递归是指一个函数在执行过程中调用自身的过程。

递归算法通常包括两个部分:递归出口和递归调用。

递归出口是指当满足某个条件时结束递归的条件,而递归调用则是指在函数内部调用自身来解决规模更小的问题。

递归算法在解决一些具有重复性结构的问题时非常高效。

例如,计算一个数的阶乘,可以使用递归算法来实现:```c#include <stdio.h>int factorial(int n) {if (n == 0 || n == 1) { //递归出口return 1;} else {return n * factorial(n - 1); //递归调用}}int main() {int n = 5;printf("The factorial of %d is %d\n", n, factorial(n));return 0;}```上述代码定义了一个计算阶乘的递归函数factorial。

在函数内部,通过递归调用来计算规模更小的问题,直到n等于0或1时返回结果。

二、回溯算法回溯算法是一种通过尝试所有可能的解来找到问题解决方法的搜索算法。

在遇到有多个解可选的情况下,回溯算法会尝试每一种可能,并通过剪枝策略来避免不必要的计算。

回溯算法通常涉及到构建决策树和遍历树上的节点。

以八皇后问题为例,考虑如何在8x8的棋盘上放置8个皇后,使得每个皇后都不会互相攻击。

下面是用回溯算法解决八皇后问题的示例代码:```c#include <stdio.h>#define N 8int board[N][N];int isSafe(int row, int col) {int i, j;// 检查当前位置的列是否安全for (i = 0; i < row; i++) {if (board[i][col] == 1) {return 0;}}// 检查当前位置的左上方是否安全for (i = row, j = col; i >= 0 && j >= 0; i--, j--) { if (board[i][j] == 1) {return 0;}}// 检查当前位置的右上方是否安全for (i = row, j = col; i >= 0 && j < N; i--, j++) { if (board[i][j] == 1) {return 0;}}return 1;}int solve(int row) {int col;if (row >= N) { // 所有行都已经安全放置皇后,找到解 return 1;}for (col = 0; col < N; col++) {if (isSafe(row, col)) {board[row][col] = 1; // 放置皇后if (solve(row + 1)) { // 递归调用return 1;}board[row][col] = 0; // 回溯,撤销放置皇后}}return 0;void printBoard() {int i, j;for (i = 0; i < N; i++) {for (j = 0; j < N; j++) {printf("%d ", board[i][j]); }printf("\n");}}int main() {if (solve(0)) {printf("Solution:\n");printBoard();} else {printf("No solution found.\n"); }return 0;}上述代码使用回溯算法来解决八皇后问题。

递归和回溯

递归和回溯
回溯算法其实是一种试探,该方法放弃关于问题规 模大小的限制,并将问题的方案按某种顺序逐一枚 举和试验
◦ 发现当前方案不可能有解时,就选择下一个方案 ◦ 倘若当前方案不满足问题的要求时,继续扩大当前方案的
规模,并继续试探 ◦ 如果当前方案满足所有要求时,该方案就是问题的一个解 ◦ 放弃当前方案,寻找下一解方案的过程称为回溯
(-,2,7)(-,-3,16)
(-,5,0)(-,0,9)
(-,3,8) (-,-2,17)
要求每个位同学,设计某种算法,包括:
◦ 算法的基本数学描述, ◦ 使用Raptor实现计算流程
◦ 一个问题的不同解法:(例如背包问题的递归、贪心、限 界分支法)
◦ 典型数据结构的应用: (堆栈、队列、链表、图、树) ◦ 时空效率分析(可以使用任何语言环境) 递交方法: 电子教室的大作业专区(讨论区: 每人一贴, 可 用回帖更新), 必须将你的题目写成标题: 使用环形队列计 算舞伴问题(防止题目和内容雷同)
输入的数据必须为“立方米”,输出必须为“元” 作为量纲(Specification)
不可接受的输入:输入值为负值,输出值为负值;
"Program testing can be used to show the presence of bugs, but never to show their absence.“ Edsger Dijkstra
=4500步 总的运行次数=((9+4500)/2) * 499=
1,124,995.5 计算复杂性:O(0.5N2)
1014070次符号评估,就是本算法的运行次数。 估算准确性,
估算运行次数,X1= 1,124,995.5 实际运行次数,X2 = 1,014,070 误差率 : ( X1/X2 -1)% =11% 误差原因分析: 第6步,是一个不完全执行语句。

python 常用算法 枚举 递归 回溯

python 常用算法 枚举 递归 回溯

标题:深入探索Python常用算法:枚举、递归和回溯在计算机科学领域,算法是解决问题的一种方法或步骤。

Python作为一种功能丰富、易于学习的编程语言,广泛应用于算法设计和实现中。

本文将深入探讨Python中常用的算法:枚举、递归和回溯,帮助读者更全面、深刻地理解这些算法,以及它们在实际问题中的应用。

1. 枚举枚举是一种常见的算法思想,它通过穷举所有可能的情况来寻找问题的解。

在Python中,我们可以利用循环来实现枚举算法,列举所有可能的组合或排列。

在解决集合中某个元素的排列组合问题时,枚举算法能够帮助我们找到所有可能的情况,从中筛选出符合条件的解。

当然,枚举算法在实际应用中可能会遇到效率低、时间复杂度高的问题,但在某些问题中,特别是规模较小的情况下,枚举算法仍然具有一定的实用性。

2. 递归递归是一种非常重要的算法思想,它通过函数自身的调用来解决复杂的问题。

在Python中,递归算法常常用于解决树、图等非线性结构的问题。

通过不断地将原问题分解为规模较小的子问题,并利用函数的递归调用来解决这些子问题,最终得到原问题的解。

然而,递归算法在实际应用中也存在一些问题,比如递归深度过深会导致栈溢出,而且递归算法的效率通常不高。

在使用递归算法时,需要注意合理控制递归深度,并对递归算法进行优化。

3. 回溯回溯是一种在解决约束满足问题时非常常见的算法思想,它通过不断尝试可能的解,并在尝试过程中进行剪枝,从而找到问题的解。

在Python中,回溯算法常常用于解决八皇后、数独等问题,这些问题都属于约束满足问题的范畴。

回溯算法的本质是一个递归搜索过程,通过不断地尝试可能的解,然后进行回退和剪枝,最终找到问题的解。

在实际应用中,回溯算法通常能够找到问题的所有解,但也需要考虑到它的时间复杂度问题,特别是在问题规模较大时。

个人观点和理解在实际问题中,枚举、递归和回溯算法都具有重要的应用价值。

虽然它们各自存在一些问题,比如枚举算法的时间复杂度高、递归算法可能导致栈溢出、回溯算法需要进行剪枝来提高效率,但在很多情况下,它们仍然是解决问题的有效手段。

递归算法步骤 -回复

递归算法步骤 -回复

递归算法步骤-回复递归算法是一种常用的计算机编程技术,它通过将问题分解为更小的子问题来求解。

在递归算法中,函数将自身作为子过程调用,直到满足某个基准(也称作递归终止条件)时停止。

本文将详细介绍递归算法的步骤,以便读者更好地理解和应用这一概念。

首先,让我们明确一下递归算法的基本思想。

递归算法通常使用一个递归函数来解决问题,这个函数会在其内部调用自身。

当递归函数被调用时,它执行一系列操作,并且针对一个更小规模的问题调用自身的函数。

这个规模更小的问题通常是原问题的一个子问题,通过递归调用逐渐解决。

递归算法的步骤可以归纳为以下几个关键点:1. 确定递归函数的参数:首先,我们需要确定递归函数的参数,并考虑如何用这些参数来表示问题的规模。

递归函数的参数通常包括原问题所需的数据,以及标识子问题规模的变量。

这些参数将在函数的调用过程中被传递和修改。

2. 确定递归终止条件:递归终止条件是递归算法中的关键步骤,它定义了递归调用何时结束的条件。

如果没有递归终止条件,递归函数将无限地调用自身,导致无法求解问题。

递归终止条件通常基于原问题的规模,当问题规模达到一定程度时,递归调用将停止。

3. 处理基本情况:基本情况是指递归终止条件下的一种特殊情况。

当问题的规模满足递归终止条件时,我们可以直接求解问题,并将解返回给上层调用。

这个过程通常被称为基本情况的处理,它标志着递归调用的结束。

4. 缩小问题规模:在递归算法中,我们需要将原问题分解为更小的子问题。

在递归函数的内部,我们可以通过改变参数的值或者其他方式,将原问题划分为规模更小的子问题。

定义良好的递归函数将确保每次递归调用处理的问题规模减小,最终达到基本情况。

5. 调用递归函数:在递归算法中,一旦确定了递归函数的参数、递归终止条件和处理基本情况的方法,我们就可以调用递归函数。

在函数的内部,我们使用适当的参数调用自身,并将返回的结果用于解决原问题。

6. 整合子问题的结果:当递归函数返回子问题的解时,我们需要将这些解整合起来,以求解原问题。

python 常用算法 枚举 递归 回溯

python 常用算法 枚举 递归 回溯

python 常用算法枚举递归回溯【原创版】目录1.引言2.Python 中的枚举算法3.Python 中的递归算法4.Python 中的回溯算法5.总结正文1.引言在编程中,算法是解决问题的核心方法。

Python 作为一门广泛应用于数据分析、人工智能和 web 开发的编程语言,掌握其常用的算法对于编程工作非常有帮助。

本文将介绍 Python 中常用的枚举算法、递归算法和回溯算法。

2.Python 中的枚举算法枚举算法,也被称为穷举算法,是在解决问题时尝试所有可能的解决方案,通过推理考虑事件发生的每一种可能,最后得出结论。

在 Python 中,我们通常使用 while 循环或者 if 语句来实现枚举算法。

例如,我们可以通过枚举算法找到 100-999 之间的所有水仙花数(即三位数,其各位数字立方和等于该数本身)。

代码如下:```pythoncount = 0for i in range(100, 1000):a = i // 100b = i % 100 // 10c = i % 10if a ** 3 + b ** 3 + c ** 3 == i:print("水仙花数:", i)count += 1print("共有", count, "个水仙花数")```3.Python 中的递归算法递归算法是一种将问题分解成规模较小的相似子问题的算法,递归函数在执行过程中直接或间接地调用自身。

Python 中的递归算法通常使用def 关键字定义。

例如,我们可以通过递归算法计算一个数的阶乘。

代码如下:```pythondef factorial(n):if n == 0 or n == 1:return 1else:return n * factorial(n - 1)um = 5print("阶乘", num, "等于", factorial(num))```4.Python 中的回溯算法回溯算法是一种试探性的搜索算法,从一条路往前走,直到走不通为止,然后回退,尝试别的路。

【实用】递归与回溯算法PPT资料

【实用】递归与回溯算法PPT资料

程序设计
1.(文件名:d4.pas)利用递归过程,将一个十进 制整数K转化为7进制整数。 测试数据: 输入:十进制数K 19 输出:7进制整数 25
2.(文件名:d5.pas)楼梯有N阶台阶,上楼可以 一步上一阶,也可以一步上二阶,计算共有多少种 不同走法。 测试数据: 输入:输入N的值 6 输出:走法总数 13
在这里,因为函数FAC的形 参是值形参,因此每调用一次 该函数,系统就为本次调用的 值形参N开辟了一个存储单元, 以便存放它的实参的值。也就 是说,对于递归函数或递归过 程,每当对它调用一次时,系 统都要为它的形式参数与局部 变量(在函数或过程中说明的 变量)分配存储单元(这是一 个独立的单元,虽然名字相同, 但实际上是互不相干的,只在 本层内有效),并记下返回的 地点,以便返回后程序从此处 开始执行。
测试数据 输入:
34 输出:
125
例5:用辗转相除法求两个自然数m,n的最大公约数。 思路:辗转相除法规定:求两个正整数m,n (m>=n)的最大公约数,应先将m除以n;求得 余数r,如果等于零,除数n就是m,n的最大公约数; 如果r不等于零,就用n除以r,再看所得余数是否 为零。重复上面过程,直到余数r为零时,则上一 次的余数值即为m,n的最大公约数。用其数学方 式描述如下:
以上(2)表示一操作依赖另一操作,所以需要用递归调 用。(4)表示已知操作(递归的终止)。
程序如下: program aa; procedure reverse; var
ch:char; begin
read(ch); if ch<>'&' then reverse; write(ch); end; begin reverse; writeln; end.

for循环、递归、回溯

for循环、递归、回溯

for循环、递归、回溯⽬录:1.简单递归定义2.递归与循环的区别与联系3.递归的经典应⽤1.简单递归定义什么叫递归?(先定义⼀个⽐较简单的说法,为了理解,不⼀定对)递归:⽆限调⽤⾃⾝这个函数,每次调⽤总会改动⼀个关键变量,直到这个关键变量达到边界的时候,不再调⽤。

⽐如说我要你先求⼀个N!的结果你说我会⽤循环啊(没错,但是现在是学递归)int factorial(int x,int ans){if(x==1)return ans;factorial(x-1,ans*x);}怎么样,对于C基础如果掌握的还⾏的话,这段代码应该很好理解。

递归,顾名思义就是“递”和“归”。

也就是说,写每⼀个递归函数的时候,都应该在写之前考虑清楚,哪⾥体现了“递”,哪⾥体现了“归”。

但是常常递归函数会⽐较复杂, “递”和“归”看起来并不是那么明显,这就需要我们进⼀步来理解递归算法的思想。

⽐如说我现在要你⽤辗转相除法求出两个数的最⼤公约数,递归函数如下:int gcd(int a,int b){return a%b==0?b:gcd(b,a%b);}这是⼀段很常⽤的代码,我们知道,在学习过程中不求甚解是最不应该的。

因此现在来仔细看⼀看。

这⾥的“递”和“归”放在同⼀⾏。

⾸先进⾏判断a==b?(我们可以想象成“归”的内容,如果这个条件符合的话)。

当然,如果不符合这个判断,那就继续“递”,也就是继续进⾏gcd(b,a%b);看到这⾥,你就会发现,递归不就是循环的另⼀种⽅式么?说对了⼀半,不过递归是⼀种思想,现在还暂时不能说透,需要⼤家先⽐较⼀下循环和递归的相同点和不同点(饭⼀⼝⼀⼝吃,别着急)2.递归与循环的区别于联系相同点:(1)都是通过控制⼀个变量的边界(或者多个),来改变多个变量为了得到所需要的值,⽽反复⽽执⾏的;(2)都是按照预先设计好的推断实现某⼀个值求取;(请注意,在这⾥循环要更注重过程,⽽递归偏结果⼀点)不同点:(1)递归通常是逆向思维居多,“递”和“归”不⼀定容易发现(⽐较难以理解);⽽循环从开始条件到结束条件,包括中间循环变量,都需要表达出来(⽐较简洁明了)。

回溯和递归

回溯和递归

回溯和递归的区别
递归就是:函数自己调用自己的操作都叫递归,递归是编程技巧;
回溯有固定的模板,是递归的一种典型用法,是一种算法思想,实际上一个类似枚举的搜索尝试过程。

回溯的模板一(排列组合)
public static List<String> list = new LinkedList<>();//
void dfs(String str, StringBuilder sb, int index)
if(index==长度){
res.add(sb.toString());
}
...通过index获取什么东西...
//第一个回溯分支
for(int i=0;i<str.length();i++){
sb.add(str.charAt(i));
dfs(str,sb,index+1);
sb.deleteCharAt(sb.length()-1);
}
//第二个回溯分支
...
·公共变量用于存储结果
·函数变量:①传递入参、②临时容器、③定位索引
·if判断长度,临时容器归档到存储结果中
·(记录访问轨迹)
·(剪枝)
·循环
·加-递-减。

递归与回溯的理解

递归与回溯的理解

递归与回溯的理解递归思路程序调⽤⾃⾝的编程技巧称为递归( recursion)。

递归做为⼀种算法在程序设计语⾔中⼴泛应⽤。

⼀个过程或函数在其定义或说明中有直接或间接调⽤⾃⾝的⼀种⽅法,它通常把⼀个⼤型复杂的问题层层转化为⼀个与原问题相似的规模较⼩的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,⼤⼤地减少了程序的代码量。

通常来说,为了描述问题的某⼀状态,必须⽤到该状态的上⼀个状态;⽽如果要描述上⼀个状态,⼜必须⽤到上⼀个状态的上⼀个状态…… 这样⽤⾃⼰来定义⾃⼰的⽅法就是递归。

写递归⼼得明⽩⼀个函数的作⽤并相信它能完成这个任务,千万不要试图跳进细节。

千万不要跳进这个函数⾥⾯企图探究更多细节,否则就会陷⼊⽆穷的细节⽆法⾃拔,⼈脑能压⼏个栈啊。

以Path sum 3为例给⼀课⼆叉树,和⼀个⽬标值,节点上的值有正有负,返回树中和等于⽬标值的路径条数,让你编写 pathSum 函数:root = [10,5,-3,3,2,null,11,3,-2,null,1],sum = 810/ \5 -3/ \ \3211/ \ \3 -21Return 3. The paths that sum to 8 are:1. 5 -> 32. 5 -> 2 -> 13. -3 -> 11------题解//给他⼀个节点和⼀个⽬标值,他返回以这个节点为根的树中,和为⽬标值的路径总数。

int pathSum(TreeNode root, int sum) {if (root == null) return 0;int pathImLeading = count(root, sum); // ⾃⼰为开头的路径数int leftPathSum = pathSum(root.left, sum); // 左边路径总数(相信他能算出来)int rightPathSum = pathSum(root.right, sum); // 右边路径总数(相信他能算出来)return leftPathSum + rightPathSum + pathImLeading;}//给他⼀个节点和⼀个⽬标值,他返回以这个节点为根的树中,能凑出⼏个以该节点为路径开头,和为⽬标值的路径总数。

递归法和回溯法

递归法和回溯法

递归法和回溯法有人说,回溯实际上是递归的展开,但实际上。

两者的指导思想并不一致。

打个比方吧,递归法好比是一个军队要通过一个迷宫,到了第一个分岔口, 有 3 条路,将军命令 3 个小队分别去探哪条路能到出口,3 个小队沿着 3 条路分 别前进, 各自到达了路上的下一个分岔口,于是小队长再分派人手各自去探路— —只要人手足够 (对照而言, 就是计算机的堆栈足够) 最后必将有人找到出口, , 从这人开始只要层层上报直属领导,最后,将军将得到一条通路。

所不同的是, 计算机的递归法是把这个并行过程串行化了。

而回溯法则是一个人走迷宫的思维模拟——他只能寄希望于自己的记忆力, 如果他没有办法在分岔口留下标记(电视里一演到什么迷宫寻宝,总有恶人去改 好人的标记)。

想到这里突然有点明白为什么都喜欢递归了, 他能够满足人心最底层的虚荣 ——难道你不觉得使用递归就象那个分派士兵的将军吗?想想汉诺塔的解法, 也 有这个倾向,“你们把上面的 N-1 个拿走,我就能把下面的挪过去,然后你们 在把那 N-1 个搬过来”。

笑谈,切勿当真。

这两种方法的例程,我不给出了,网上很多。

我只想对书上的递归解法发表 点看法,因为书上的解法有偷梁换柱的嫌疑——迷宫的储存不是用的二维数组, 居然直接用岔路口之间的连接表示的——简直是人为的降低了问题的难度。

实际 上,如果把迷宫抽象成(岔路口)点的连接,迷宫就变成了一个“图”,求解入 口到出口的路线, 完全可以用图的遍历算法来解决,只要从入口 DFS 到出口就可 以了; 然而, 从二维数组表示的迷宫转化为图是个很复杂的过程。

并且这种转化, 实际上就是没走迷宫之前就知道了迷宫的结构,显然是不合理的。

对此,我只能 说这是为了递归而递归,然后还自己给自己开绿灯。

但迷宫并不是只能用上面的方法来走,前提是,迷宫只要走出去就可以了, 不需要找出一条可能上的最短路线——确实,迷宫只是前进中的障碍,一旦走通了,没人走第二遍。

递归回溯算法

递归回溯算法

递归回溯算法一、什么是递归回溯算法?递归回溯算法是一种常用于解决问题的算法,主要应用于搜索和遍历问题。

它通过不断地尝试所有可能的解决方案,并在发现无解时进行回溯,直到找到符合条件的解决方案。

二、递归回溯算法的基本思想递归回溯算法的基本思想是:从问题的初始状态开始,通过一系列的状态转移操作,不断地搜索可能的解决方案,直到找到符合条件的解决方案或者确定无解。

具体来说,递归回溯算法通常采用递归方式实现。

在每一次递归过程中,程序会尝试一个新的选择,并进入下一层递归。

如果当前选择无法得到有效解决方案,则程序将进行回溯操作,撤销当前选择,并返回上一层递归继续尝试其他选择。

三、适用场景递归回溯算法通常用于以下场景:1. 求所有可能的排列或组合;2. 求最优解或符合某些条件的最优解;3. 搜索图或树等数据结构中符合某些条件的节点或路径;4. 解数独等复杂问题。

四、递归回溯算法的实现步骤递归回溯算法的实现步骤通常包括以下几个方面:1. 确定问题的状态表示方式,以及每个状态可能的选择;2. 采用递归方式实现搜索过程,每次递归尝试一个新的选择,并进入下一层递归;3. 在每一层递归中,判断当前选择是否符合条件,如果符合则继续进行下一层递归;如果不符合,则进行回溯操作,撤销当前选择,并返回上一层递归继续尝试其他选择;4. 在最后一层递归中,得到符合条件的解决方案。

五、示例代码以下是一个求解八皇后问题的示例代码:```#include <iostream>using namespace std;const int N = 8; // 棋盘大小int queen[N]; // 存放皇后位置int cnt = 0; // 记录解的个数// 判断当前位置是否可以放皇后bool check(int row, int col) {for (int i = 0; i < row; i++) {if (queen[i] == col || queen[i] - col == i - row || queen[i] - col == row - i)return false;}return true;}// 搜索解决方案void dfs(int row) {if (row == N) { // 得到一个解cnt++;cout << "Solution " << cnt << ":" << endl; for (int i = 0; i < N; i++) {for (int j = 0; j < N; j++) {if (queen[i] == j) cout << "Q ";else cout << ". ";}cout << endl;}return;}for (int col = 0; col < N; col++) { // 枚举每一列 if (check(row, col)) { // 如果当前位置可以放皇后 queen[row] = col; // 放置皇后dfs(row + 1); // 进入下一层递归queen[row] = -1; // 回溯操作,撤销当前选择 }}}int main() {memset(queen, -1, sizeof(queen)); // 初始化棋盘为空dfs(0); // 从第一行开始搜索解决方案return 0;}```六、算法分析递归回溯算法的时间复杂度通常较高,因为它需要搜索所有可能的解决方案。

递归回溯算法

递归回溯算法

递归回溯算法简介递归回溯算法是一种解决问题的算法思想,它通过不断地尝试所有可能的解决方案,并在每一步中进行回溯,即撤销上一步的选择,直到找到满足条件的解。

这种算法思想通常用于解决组合优化问题,如全排列、子集、背包等。

概念解析•递归:递归是指一个函数调用自身的过程。

在递归回溯算法中,递归函数通常用于尝试解决问题的每一步。

•回溯:回溯是指当无法继续前进时,回退到上一层的过程。

在递归回溯算法中,回溯通常用于撤销上一步的选择,以尝试其他可能的解决方案。

算法框架递归回溯算法的框架通常包括以下几个步骤:1.确定递归函数的输入参数和返回值:通常需要传入当前的状态和已经做出的选择,返回解决方案或最优解。

2.确定递归函数的终止条件:当满足终止条件时,停止继续递归,返回解决方案或最优解。

3.确定每一步的选择范围:根据实际情况,确定可以做出的选择范围。

4.根据选择范围,在每一步中进行递归调用:对每一个选择进行递归调用,尝试解决问题的下一步。

5.在每一步中进行回溯:如果当前选择导致无法继续前进,进行回溯,撤销上一步的选择,尝试其他可能的解决方案。

6.处理结果:根据实际需求,对每一个解决方案进行处理,如输出结果、更新最优解等。

应用场景递归回溯算法在很多问题中都有应用,特别是在组合优化问题中更为常见。

下面列举几个常见的应用场景:1. 全排列全排列是指将一组元素进行排列,列出所有可能的排列情况。

对于一个含有n个元素的集合,全排列的结果共有n!种可能。

算法思路:1.从集合中选择一个元素作为当前位置的元素。

2.使用递归算法求解剩余元素的全排列。

3.当集合中只剩下一个元素时,输出当前排列情况。

4.撤销上一步的选择,尝试其他可能的排列情况。

2. 子集子集是指在一个集合中,取出部分或全部元素形成的集合。

对于一个含有n个元素的集合,子集的结果共有2^n种可能。

算法思路:1.不选择当前元素,进入下一层递归。

2.选择当前元素,进入下一层递归。

迭代与递归和还原的关系

迭代与递归和还原的关系

迭代与递归和还原的关系
迭代、递归和还原在计算机科学和数学中都有其特定的应用和关系,以下是它们之间的一些关系:
1. 递归与迭代:
递归是一种编程技巧,程序调用自身以解决问题。

递归将问题分解为更小的子问题,并逐个解决这些子问题,直到达到基本情况。

迭代则是通过重复执行一系列操作来解决问题,这些操作会根据某些条件进行修改,直到满足某个结束条件。

在理论上,递归和迭代的时间复杂度可能是相同的,但在实际应用中,由于函数调用和函数调用堆栈的开销,递归的效率通常较低。

理论上,递归和迭代可以相互转换。

例如,n的阶乘问题可以通过递归或迭代方法解决。

2. 迭代与还原:
还原通常指的是将一个复杂的问题或系统简化为一个或多个更简单的问题或子系统。

当使用迭代方法解决问题时,通常会将问题分解为一系列的步骤或操作,每一步都试图解决一部分问题,直到达到最终解决方案。

这种分步骤、分阶段解决问题的过程可以看作是一种还原的过程。

迭代方法通过将问题分解为更小的部分来解决问题,从而将一个复杂的问题还原为其基本的组成部分。

综上所述,递归、迭代和还原在解决问题的方法上有所不同,但它们在某些情况下可以相互关联或转换。

还原的概念可以看作是迭代方法的一个方面,因为迭代方法通过逐步解决较小的问题来还原问题的解决方案。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

递归的特殊情况: 无法按照设想的逼近手段‚顺利‛递进至边界,此路不通! 或者要求找出所有‚畅通‛路径(穷举!) 回溯:回退几步,换条路再走,直至走通(或者走完所有可 能路径)
13
递归的特殊情况:回溯
回溯(backtracking)的基本思想: 为了求得问题的解,先选择某一种可能情况向前探索 在探索过程中,一旦发现原来的选择是错误的,就退回一步 重新选择,继续向前探索 如此反复进行,直至得到解或证明无解 现实世界的走迷宫
计算概论 之 程序设计基础 函数、递推与递归(4)
黄罡 北京大学信息科学技术学院
上一讲内容回顾
递归是从目标结果(未知项)出发:直接假设存在一个递归函 数可以求出目标结果 计算N的阶乘:int fact(int n) 求两个正整数的最大公因数:int mcf(int x,int y) 汉诺塔:void moveNDisks(int disks, char from, char to, char via) 如何寻找递归边界:考察递归函数的参数为0、1或2个参数相等 时,是否可以直接得出明确的结果 计算N的阶乘:if(x==1) return 1 求两个正整数的最大公因数:if(y==0) return x; 汉诺塔:if(disks==1) moveOneDisk(from,to); 不是所有的递归函数参数都可作为边界, 只有那些表示问题规模的参数才是考察对象
7
POJ第2756题:二叉树
解题思路2(非递归)
最大共同节点就是x和y分别 走向根节点的路上相遇的第 一个节点 除根节点1以外,任意节点x 的上层节点是x/2,因此, 不停地整除2就可以从节点 x‚沿路走到‛根节点 x和y谁先走?大在小的同层 或下层,谁大谁先走
8
POJ第2756题:二叉树
14
递归函数设计技巧:回溯
递归就是利用嵌套调用的能力,对函数自身不停地嵌套调用(递进),直至 某个条件成立而停止嵌套调用,然后逐层返回(递归) 递归是从目标结果(未知项)出发 • 直接假设存在一个递归函数可以求出目标结果
如何寻找递归边界? • 考察递归函数的参数为0、1或2个参数相等时,是否可以 直接得出明确的结果 • 回溯意味着,可能存在某些‚墙‛,碰到这些墙则意味着 ‚此路不通‛ 如何逐步逼近递归边界? • 找出使得递归函数的参数不断减小的规则,且需确保这些 规则‚完整‛覆盖了参数的所有可能的取值 • 回溯意味着,当进行了N次逼近后,如果无法进一步逼近 边界(碰墙),则回退到N-1次逼近的情况,选择另外一 条路重新逼近。最终,或者成功抵达递归边界,或者无解
• 求二叉树的最大共同节点:int common(int x, int y) { if(x==y) return x; }
10
除根节点1以外,任意节点x的上层节点是x/2(参数值减小) 不停地整除2就可以从节点x“沿路走到‛根节点 x和y谁先走?谁大谁先走:大在小的同层或下层(完整覆盖) 最大共同节点就是x和y分别走向根节点的路上相遇的第一个节点(x==y)
# . . . . . . . #
. # . . . . . # .
17
POJ第2816题:红与黑
有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷 砖。你站在其中一块黑色的瓷砖上,只能向相邻的黑色瓷砖移动 。请写一个程序,计算你总共能够到达多少块黑色的瓷砖。
15
POJ第2816题:红与黑
有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷 砖。你站在其中一块黑色的瓷砖上,只能向相邻的黑色瓷砖移动 。请写一个程序,计算你总共能够到达多少块黑色的瓷砖。
Input
包括多个数据集合。每个数据集合的第一行是两个整数W 和H,分别表示x方向和y方向瓷砖的数量。W和H都不超过 20。在接下来的H行中,每行包括W个字符。每个字符表 示一块瓷砖的颜色,规则如下 1)‘.’:黑色的瓷砖; 2)‘#’:红色的瓷砖; 3) ‘@’:黑色的瓷砖,并且你站在这块瓷砖上。该字符在 每个数据集合中唯一出现一次。 Output 当在一行中读入的是两个零时,表示输入结束。 45 对每个数据集合,分别输出一行,显示你从初始位置出发 能到达的瓷砖数(记数时包括初始位置的瓷砖)。 Input 69 . . . . . . . . . . . . . . . . . . . . . . . . . . . . # @ . . . # . . 00
POJ第2756题:二叉树
如何逐步逼近递归边界?找出使得递归函数的参数不断减小的 规则,且需确保这些规则完整覆盖参数所有可能的取值
• 计算N的阶乘:int fact(int x) { fact(x)=x*fact(x-1); } • 求两个正整数的最大公因数:int mcf(int x,int y) { mcf(x,y) = mcf(y,x%y); } • 汉诺塔:void moveNDisks(int disks, char from, char to, char via) { moveNDisks(); moveOneDisk(); moveNDisks(); }
5
POJ第2756题:二叉树
解题思路1(非递归): 1)求出x和y的路径
2)从顶点(一定是1) 开始,逐个比较x和y路 径上的结点 如果发现不同点,则输 出上一层结点 否则,输出路径较短/值 较小的x或y
6
POJ第2756题:二叉树
解题思路2(非递归)
最大共同节点就是x和y分别 走向根节点的路上相遇的第 一个节点 除根节点1以外,任意节点x 的上层节点是x/2,因此, 不停地整除2就可以从节点 x‚沿路走到‛根节点 x和y谁先走?大在小的同层 或下层,谁大谁先走
3
本讲概览
递归与非递归:二叉树 递归的特殊情况:回溯
POJ第2816题:红与黑 教材例题:分书
4
POJ第2756题:二叉树
Input 输入只有一行,包括两个正整数x 和y,这两个正整数都不大于1000。 Output 输出只有一个正整数xi。
除根节点1以外,任意节点x的 上层节点是x/2 (整除)
递归是从目标结果(未知项)出发,即,直接假设存在一个递 归函数可以求出目标结果
• 计算N的阶乘:int fact(int n) • 求两个正整数的最大公因数:int mcf(int x,int y) • 汉诺塔:void moveNDisks(int disks, char from, char to, char via)
POJ第2756题:二叉树
除根节点1以外,任意节点x的上层节点是x/2 不停地整除2就可以从节点x“沿路走到‛根节点 x和y谁先走?谁大谁先走:大在小的同层或下层 最大共同节点就是x和y分别走向根节点的路上相 遇的第一个节点
12
递归的特殊情况:回溯
递归就是利用嵌套调用的能力,对函数自身不停地嵌套调用(递 进),直至某个条件成立而停止嵌套调用,然后逐层返回(递归) 常见的递归可以按照设想的逼近手段‚顺利‛递进至边界 形象地,递归就是沿着1条或多条预想路径走向边界,抵达边 界后原路返回
• 求二叉树的最大共同节点:int common(int x, int y)
9
除根节点1以外,任意节点x的上层节点是x/2(参数值减小) 不停地整除2就可以从节点x“沿路走到‛根节点 x和y谁先走?谁大谁先走:大在小的同层或下层(完整覆盖) 最大共同节点就是x和y分别走向根节点的路上相遇的第一个节点
2
上一讲内容回顾
如何逐步逼近递归边界:找出使得递归函数的参数不断减小的规 则,且需确保这些规则完整覆盖参数的所有可能的取值 计算N的阶乘:int fact(int x) • if(x!=1) return x*fact(x-1); 求两个正整数的最大公因数:int mcf(int x,int y) • if(y!=0) return mcf(y,x%y); 汉诺塔:void moveNDisks(int disks, char from, char to, char via) • moveNDisks(); moveOneDisk(); moveNDisks(); 很多递归不是单一路径逼近边界,即,每个规模的求解需要多 次调用小规模的递归函数多次(不一定是N-1规模),此时需 要考察所有可能的路径,如汉诺塔、逆波兰表达式 有些路径最终可能无法到达边界,此时需要回退到另一条可能 的路径,再次尝试逼近边界,此即所谓的‚回溯‛,如迷宫、 分书、八皇后
‚总共‛意味着要走通所有路径(穷举) 包括多个数据集合。每个数据集合的第一行是两个整数W 递归是从目标结果(未知项)出发 和H,分别表示x方向和y方向瓷砖的数量。W和H都不超过 直接假设存在一个递归函数可以求出目标结果 20。在接下来的H行中,每行包括W个字符。每个字符表 示一块瓷砖的颜色,规则如下 • 在某个坐标上可到达的黑砖数: 1)‘.’:黑色的瓷砖; 2)‘#’:红色的瓷砖; 3) int move(int x, int y) ‘@’:黑色的瓷砖,并且你站在这块瓷砖上。该字符在 Input 69 . . . . . . . . . . . . . . . . • 计算N的阶乘:int fact(int n) 每个数据集合中唯一出现一次。 . . . . • 求两个正整数的最大公因数:int mcf(int x,int y) Output 当在一行中读入的是两个零时,表示输入结束。 45 . . . . • 求二叉树的最大共同节点:int common(int x, int y) Output • 汉诺塔:void moveNDisks(int disks, char from, char to, char via) . . . . 对每个数据集合,分别输出一行,显示你从初始位置出发 # @ . . 能到达的瓷砖数(记数时包括初始位置的瓷砖)。 . # . . 00
相关文档
最新文档