1.汉诺塔
根据汉诺塔 - 维基百科 介绍
1.1 背景
最早发明这个问题的人是法国数学家爱德华·卢卡斯。
传说越南河内某间寺院有三根银棒,上串 64 个金盘。寺院里的僧侣依照一个古老的预言,以上述规则移动这些盘子;预言说当这些盘子移动完毕,世界就会灭亡。这个传说叫做梵天寺之塔问题(Tower of Brahma puzzle)。但不知道是卢卡斯自创的这个传说,还是他受他人启发。
若传说属实,僧侣们需要 (2的64次方-1)步才能完成这个任务;若他们每秒可完成一个盘子的移动,就需要 5849 亿年才能完成。整个宇宙现在也不过 137 亿年。
这个传说有若干变体:寺院换成修道院、僧侣换成修士等等。寺院的地点众说纷纭,其中一说是位于越南的河内,所以被命名为“河内塔”。另外亦有“金盘是创世时所造”、“僧侣们每天移动一盘”之类的背景设定。
1.2 规则与问题
有三根杆子A,B,C。A杆上有 N 个 (N>1) 穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至 C 杆:
1.每次只能移动一个圆盘;
2.大盘不能叠在小盘上面。
提示:可将圆盘临时置于 B 杆,也可将从 A 杆移出的圆盘重新移回 A 杆,但都必须遵循上述两条规则。
问:如何移?最少要移动多少次?
思路:为了将A柱中的n个圆盘移动到C柱上去,我们可肯定要先把n-1个圆盘移动到B柱上去,因为只有这样做,我们才能将A柱上最大的圆盘移动到C柱上,所以我们第一个目标就是把A柱上的n-1个圆盘通过C移动到B柱上去。完成这一步后,我们就要把B柱上的(圆盘数-1)移动到C柱上,为了达成目的,是不是就要借助A柱来完成。由此递归的逻辑就清晰了,最后我们就要确定递归的退出条件了,当n == 1时,不需要在减了,这一步的操作已经一目了然了,我们只需要把当前认为A柱上的圆盘数移动到C柱即可。
#include <stdio.h>
void Move(char A,char B,char C,int n)
{
if(n == 1)
{
printf("%c->%c\n",A,C);
}
else
{
Move(A,C,B,n-1);//把A柱上的n-1个圆盘通过C柱移动到B盘
printf("%c->%c\n",A,C);
Move(B,A,C,n-1);//把B柱上的n-1个圆盘通过A柱移动到C盘
}
}
int main()
{
char A = 'A',B = 'B',C = 'C';//定义三个柱分别为A,B,C
int n = 0;
scanf("%d",&n);//要移动多少个圆盘
Move(A,B,C,n);//
return 0;
}
//当n==3时的打印结果
/*
A->C
A->B
C->B
A->C
B->A
B->C
A->C
*/
当n == 3时的效果如图
2.青蛙跳台阶
2.1题目
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
2.2递归方法
思路
现在你要跳上第n阶台阶,你会从哪阶台阶跳上去呢,因为青蛙可以跳1阶也可以跳两阶所以为了跳上第n阶,那么青蛙一定来自n-1阶或n-2阶台阶。同理为了跳上n-1阶台阶,青蛙又一定来自n-2或者n-3阶台阶…以此类推,我们就把问题转化成了一个个更小的子问题了。所以这道题目可以使用递归来解决,在写代码前,我们还要确定递归的终止条件,当青蛙为了跳上1阶台阶我们肯定能知道只有一种可能,要跳上2阶台阶有两种可能,一种是从0阶开始跳,一种是先跳到1阶再跳到2阶,这就是递归终止条件。
#include <stdio.h>
int Jump(int n)
{
if(n == 1)
return 1;
if(n == 2)
return 2;
return Jump(n-1)+Jump(n-2);
}
int main()
{
int n = 0;
scanf("%d",&n);
int ret = Jump(n);
}
2.3 动态规划
不觉得这题和斐波那契数列很像吗?斐波那契数列的公式是f(n) = f(n-1)+f(n-2)(n>2)
这里的公式也是如此,不过不同的是数列的第一个值和第二个值不相同。
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
int a = 1, b = 2;
int c = 2;
for (int i = 2; i < n; ++i)
{
c = a + b;
a = b;
b = c;
}
printf("%d\n", c);
return 0;
}