汉诺塔
大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着n片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘
解决公式
- 公式法:移动次数f(n)=2n-1
- 递推法:n个圆盘的移动次数等于把上面n-1个圆盘移动到第二根柱子上,然后将第n个圆盘移动到第三根柱子,所以有递推公式f(n)=2f(n-1)+1
注意!!!,若汉诺塔加上只能在相邻柱子移动的条件话,n个圆盘移动次数等于f(n)=3*f(n-1)+2
,边界f(1)=2
。
#include<iostream>
#include<algorithm>
using namespace std;
int f(int n){
if(n==1) return 1;
else return 2*f(n-1)+1;
}
int main(){
int n;
cin>>n;
cout<<"递归法答案:"<<f(n)<<endl;
cout<<"公式法答案:"<<pow(2,n)-1<<endl;
return 0;
}
PS:描述每一步具体移动方法的代码(递归方法)
#include<iostream>
using namespace std;
int c=0;
void move(string x,int n,string z){
cout<<"第"<<++c<<"次移动:\t"<<n<<"号圆盘\t"<<x<<"->"<<z<<endl;
}
void hanoi(int n,string x,string y,string z){
if(n==1) move(x,1,z);//圆盘只有一个时,直接从x移动到z
else{
hanoi(n-1,x,z,y); //把上面的n-1个圆盘通过z由x移动到y
move(x,n,z); //把第n个圆盘从x移动到z
hanoi(n-1,y,x,z); //把上面的n-1个圆盘通过y由x移动到z
}
}
/*
参数说明
输入一个数字代表圆盘个数
*/
int main(){
int num;
cin>>num;
hanoi(num,"第1立柱","第2立柱","第3立柱");
return 0;
}
/*测试数据*/6
第1次移动: 1号圆盘 第1立柱->第2立柱
第2次移动: 2号圆盘 第1立柱->第3立柱
第3次移动: 1号圆盘 第2立柱->第3立柱
第4次移动: 3号圆盘 第1立柱->第2立柱
第5次移动: 1号圆盘 第3立柱->第1立柱
第6次移动: 2号圆盘 第3立柱->第2立柱
第7次移动: 1号圆盘 第1立柱->第2立柱
第8次移动: 4号圆盘 第1立柱->第3立柱
第9次移动: 1号圆盘 第2立柱->第3立柱
第10次移动: 2号圆盘 第2立柱->第1立柱
第11次移动: 1号圆盘 第3立柱->第1立柱
第12次移动: 3号圆盘 第2立柱->第3立柱
第13次移动: 1号圆盘 第1立柱->第2立柱
第14次移动: 2号圆盘 第1立柱->第3立柱
第15次移动: 1号圆盘 第2立柱->第3立柱
第16次移动: 5号圆盘 第1立柱->第2立柱
第17次移动: 1号圆盘 第3立柱->第1立柱
第18次移动: 2号圆盘 第3立柱->第2立柱
第19次移动: 1号圆盘 第1立柱->第2立柱
第20次移动: 3号圆盘 第3立柱->第1立柱
第21次移动: 1号圆盘 第2立柱->第3立柱
第22次移动: 2号圆盘 第2立柱->第1立柱
第23次移动: 1号圆盘 第3立柱->第1立柱
第24次移动: 4号圆盘 第3立柱->第2立柱
第25次移动: 1号圆盘 第1立柱->第2立柱
第26次移动: 2号圆盘 第1立柱->第3立柱
第27次移动: 1号圆盘 第2立柱->第3立柱
第28次移动: 3号圆盘 第1立柱->第2立柱
第29次移动: 1号圆盘 第3立柱->第1立柱
第30次移动: 2号圆盘 第3立柱->第2立柱
第31次移动: 1号圆盘 第1立柱->第2立柱
第32次移动: 6号圆盘 第1立柱->第3立柱
第33次移动: 1号圆盘 第2立柱->第3立柱
第34次移动: 2号圆盘 第2立柱->第1立柱
第35次移动: 1号圆盘 第3立柱->第1立柱
第36次移动: 3号圆盘 第2立柱->第3立柱
第37次移动: 1号圆盘 第1立柱->第2立柱
第38次移动: 2号圆盘 第1立柱->第3立柱
第39次移动: 1号圆盘 第2立柱->第3立柱
第40次移动: 4号圆盘 第2立柱->第1立柱
第41次移动: 1号圆盘 第3立柱->第1立柱
第42次移动: 2号圆盘 第3立柱->第2立柱
第43次移动: 1号圆盘 第1立柱->第2立柱
第44次移动: 3号圆盘 第3立柱->第1立柱
第45次移动: 1号圆盘 第2立柱->第3立柱
第46次移动: 2号圆盘 第2立柱->第1立柱
第47次移动: 1号圆盘 第3立柱->第1立柱
第48次移动: 5号圆盘 第2立柱->第3立柱
第49次移动: 1号圆盘 第1立柱->第2立柱
第50次移动: 2号圆盘 第1立柱->第3立柱
第51次移动: 1号圆盘 第2立柱->第3立柱
第52次移动: 3号圆盘 第1立柱->第2立柱
第53次移动: 1号圆盘 第3立柱->第1立柱
第54次移动: 2号圆盘 第3立柱->第2立柱
第55次移动: 1号圆盘 第1立柱->第2立柱
第56次移动: 4号圆盘 第1立柱->第3立柱
第57次移动: 1号圆盘 第2立柱->第3立柱
第58次移动: 2号圆盘 第2立柱->第1立柱
第59次移动: 1号圆盘 第3立柱->第1立柱
第60次移动: 3号圆盘 第2立柱->第3立柱
第61次移动: 1号圆盘 第1立柱->第2立柱
第62次移动: 2号圆盘 第1立柱->第3立柱
第63次移动: 1号圆盘 第2立柱->第3立柱
汉诺双塔
在汉诺塔的基础上,每种大小的圆盘各有两个,这两个相同的圆盘不进行区分
解决公式
- 公式法:移动次数f(n)=2n+1-2
- 递推法:n个圆盘的移动次数等于把上面2(n-1)个圆盘移动到第二根柱子上,然后将第n个大小的两个圆盘移动到第三根柱子,所以有递推公式f(n)=2f(n-1)+2
#include<iostream>
#include<algorithm>
using namespace std;
int f(int n){
if(n==1) return 2;
else return 2*f(n-1)+2;
}
int main(){
int n;
cin>>n;
cout<<"递归法答案:"<<f(n)<<endl;
cout<<"公式法答案:"<<pow(2,n+1)-2<<endl;
return 0;
}
写给自己
注意:很多关于汉诺塔的题目测试数据都比较大,甚至用long long都放不下,所以得使用高精度
例如:https://www.dotcpp.com/oj/problem1109.html
#include<iostream>
using namespace std;
int num[100]={0};
void mul(){
int pre=0;
for(int i=99;i>=0;i--){
num[i]=num[i]*2+pre;
if(num[i]>=10){
num[i]-=10;
pre=1;
}
else pre=0;
}
}
int main(){
int n;
cin>>n;
num[99]=1;
for(int i=0;i<n+1;i++) mul();
num[99]-=2;
bool flag=false;
for(int i:num){
if(!flag&&i!=0) flag=true;
if(flag) cout<<i;
}
return 0;;
}