北航OJ-2014级第1次算法上机题解
A. 零崎的人间冒险Ⅰ
题目描述
零崎最近一段时间非常无聊,于是他决定进行一场冒险,然而无聊的人遇到的冒险也非常的无聊,他的冒险刚刚开始就要结束了。理由也非常的无聊,因为一个无聊的大魔王决定用一个非常有魔(wu)力(liao)的方式毁灭世界。
魔王有三个具有魔(wu)力(liao)的杆,暂时称为ABC,还有n个具有魔(wu)力(liao)的大小全都不同的盘子,这些盘子按照大小顺序放在A杆上,现在魔王要用具有魔(wu)力(liao)的方式移动到C杆,移动的过程中,小的盘子仍然只能摆在大的盘子上面而不能发生错乱,否侧魔王的魔法就会失灵。 然而魔王似乎想找一个无聊的人来替他完成这个魔法,而无聊的零崎也觉得这个事情非常的无聊,干脆就决定还是让你们去做。
零崎也不知道这个无聊的魔王到底有多少个有魔(wu)力(liao)的盘子,所以他说多少个你们就当是多少个吧。
输入
多组数据,每组一个数字n表示魔王的盘子数。
输出
对于每组数据,输出为魔王魔法发动后盘子移动的过程,两组输出之间用空行隔开。
输入样例
1
2
输出样例
A to C
A to B
A to C
B to C
解题思路:
这道题考查递归。
由于数据结构上机中已经遇到多次,所以这里只是简单回顾汉诺塔递归算法的整体思路:
Case 1:当A塔上只有一个盘子时,只需要将 A塔上的一个盘子移到 C塔上。
Case 2:当A塔上有n个盘子时(n>1),先将A塔上编号1至n-1的盘子(共n-1个)移动到B塔上(借助C塔),然后将A塔上最大的n号盘子移动到C塔上,最后将B塔上的n-1个盘子移动到C塔上。
解题代码
#include <stdio.h>
//hanoi函数的功能:将 n 个盘子从 A 移到 C 的过程展示出来,柱子 B 起到辅助移动的作用
void hanoi(int n, char A, char B, char C)
{
if(n == 1)
printf("%c to %c\n", A, C);
else
{
hanoi(n-1, A, C, B);
printf("%c to %c\n", A, C);
hanoi(n-1, B, A, C);
}
}
int main()
{
int n;
while(scanf("%d", &n) != EOF)
{
hanoi(n, 'A', 'B', 'C');
printf("\n");
}
}
B. 零崎的人间冒险Ⅱ
题目描述
零崎本以为他的无聊冒险马上就要结束了,然而实际上距离魔王的魔法成功发动还有很久很久,于是他的无聊冒险还可以继续……
无聊的零崎需要给自己的冒险找点事做,然而实际上他的日常非常平和,如果说有什么意外的话,那就是他去打麻将了。
零崎在玩一种叫做日式麻将的竞技游戏,然而无聊的零崎总是遭遇别人立直需要防守的场面。零崎在防守时,会跟打现物和搏筋兜牌两种技能,然而为了不被婊得太惨,零崎不会连续搏筋兜牌。也就是说,零崎任意两次选择中不会都是搏筋兜牌。
那么对于n次舍牌,无聊的零崎会有多少种选择?
因为无聊的零崎可以打很久的麻将,所以n可能很大,无聊的零崎决定只要结果对100007求模后的选择数。
输入
多组输入数据,每组一个数字n,1<=n<=Int_MAX
输出
每组一行,只需要选择种数对100007求模后的结果。
输入样例
1
2
输出样例
2
3
解题思路
Part 1 递推公式的推导
我们用O和X分别表示现物和搏筋兜牌。
假设有3次舍牌,我们可以很容易地枚举出所有排列方式:OOO, OOX, OXO, XOO, XOX,我们把每一个这样的一个序列叫做一种舍牌方式。
为了方便讨论,我们给出如下定义:
F(n) = n次舍牌中不同的舍牌方式数
比如上面的例子中,F(3) = 5。
我们来尝试推导具有普适性的公式:
假设F(n-2)种舍牌方式中,有m次以现物结束(类似于OXOXXX……O),F(n-2) - m次以搏筋兜牌结束(类似于OXOXXX……X)。
对于类似OXOXXX……O的舍牌方式,下一次舍牌既可以是O也可以是X,所以下一次有2*m中舍牌方式;对于类似OXOXXX……X的舍牌方式,下一次只能是O,所以下一次舍牌有F(n-2) - m种方式。
我们把两种舍牌方式数相加,就得到:
同理,由上面的推理结论,F(n-1)中有F(n-2)次以O结束,m次以X结束,所以: