算法训练 Hanoi问题
Description
如果将课本上的Hanoi塔问题稍做修改:仍然是给定N只盘子,3根柱子,但是允许每次最多移动相邻的M只盘子(当然移动盘子的数目也可以小于M),最少需要多少次?
例如N=5,M=2时,可以分别将最小的2个盘子、中间的2个盘子以及最大的一个盘子分别看作一个整体,这样可以转变为N=3,M=1的情况,共需要移动7次。
Input
输入描述:
输入数据仅有一行,包括两个数N和M(0<=M<=N<=8)
输入样例:
5 2
Output
输出描述:
仅输出一个数,表示需要移动的最少次数
输出样例:
7
Hint
HINT:时间限制:1.0s 内存限制:512.0MB
Source
蓝桥杯练习系统 ID: 108 原题链接: http://lx.lanqiao.cn/problem.page?gpid=T108
Submit
1、复习
先复习传统的 Hanoi问题 的实现,与本题不同在于每次只允许移动一个盘子 。
提一句这个算法涉及了递归和分治知识点 。
#include <iostream>
using namespace std;
void move(char &x, char &y, int &ans) {
//执行移动盘子的操作
cout << x << "->" << y << endl;
ans++;
}
void hanoi(int n,char one, char two, char three, int &ans) {
//将n个盘从one座借助two座,移到three座
if(n==1) {//只有 1 个盘直接移,不需要借助
move(one, three, ans);
}
else {
hanoi(n-1, one, three, two, ans);
move(one, three, ans);
hanoi(n-1, two, one, three, ans);
}
}
2、思路一:
递归 + 分治
把 n 个盘中的每 m个想成一个整体,就变成了传统的只能一次移动一个盘的 Hanoi问题
#include <iostream>
#include <cmath>
using namespace std;
void move(char &x, char &y, int &ans) {
//执行移动盘子的操作
//cout << x << "->" << y << endl;
ans++;
}
void hanoi(int n,char one, char two, char three, int &ans, int &m) {
//将n个盘从one座借助two座,移到three座
if(n<=m) { //m个想成一个整体
move(one, three, ans);
}
else {
hanoi(n-m, one, three, two, ans, m);
move(one, three, ans);
hanoi(n-m, two, one, three, ans, m);
}
}
3、思路二:
公式
我们知道传统 Hanoi问题 求移动次数有公式,就是:移动 n 个盘子要经历 步
那么对于本题而言,这个公式是什么呢?
如题目所言,N=5,M=2时,可以分别将最小的2个盘子、中间的2个盘子以及最大的一个盘子分别看作一个整体,这样可以转变为N=3,M=1的情况,共需要移动7次。
又如n=5,m=3时,三盘合1个,剩余的2盘合1,也可视为传统的移n=2问题。
依据这个道理也就有了:移动 n 个盘子,并限制每次最多移动 m 要经历 步
利用cmath函数库:四舍五入RoundEx() 向上取整ceil() 向下取整floor()
#include <iostream>
#include <cmath>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
cout << pow(2, ceil(n/(double)m))-1;
return 0;
}
浙公网安备 33010602011771号