汉诺塔
递归算法:
#include <iostream>
using namespace std;
int i=1;
void move(int n,char a,char b){
//move n from a to b
cout<<"#"<<i++<<". "<<n<<": "<<a<<"->"<<b<<endl;
}
void hanoi(int n,char x,char y,char z){
if(n==1)
move(1,x,z);
else{
hanoi(n-1,x,z,y);
move(n,x,z);
hanoi(n-1,y,x,z);
}
}
int main() {
int n;
cin>>n;
hanoi(n,'x','y','z');
return 0;
}
还有一种使用STL栈的方法,不过没有递归快,因为递归就是使用“递归工作栈”实现的。递归的方式函数调用比较少,就是调用它本身。
迭代法:
一号柱有 n 个盘子,叫做源柱.移往 3 号柱,叫做目的柱.2 号柱叫做中间柱.
全部移往 3 号柱要 f(n) =(2^n)- 1 次.
最大盘 n 号盘在整个移动过程中只移动一次,n-1 号移动 2 次,i 号盘移动
2^(n-i)次.
1号盘移动次数最多,每 2次移动一次.
第 2k+1次移动的是 1号盘,且是第 k+1 次移动 1号盘.
第 4k+2次移动的是 2号盘,且是第 k+1 次移动 2 号盘.
......
第(2^s)k+2^(s-1)移动的是 s号盘,这时 s号盘已被移动了 k+1 次.
每 2^s 次就有一次是移动 s 号盘.
第一次移动 s号盘是在第 2^(s-1)次.
第二次移动 s 号盘是在第 2^s+2^(s-1)次.
......
第 k+1 次移动 s 号盘是在第 k*2^s+2^(s-1)次.
1--2--3--1 叫做顺时针方向,1--3--2--1 叫做逆时针方向.
最大盘 n号盘只移动一次:1--3,它是逆时针移动.
n-1 移动 2次:1--2--3,是顺时针移动.
如果 n和 k奇偶性相同,则 k号盘按逆时针移动,否则顺时针.
例题:HDU 2511 汉诺塔 X
#include <iostream>
using namespace std;
int main(){
int i, k;
cin>>k;
for( i=0; i < k; i++ ){
int n, l;
__int64 m, j;
__int64 s, t;
cin>>n>>m;
s = 1; t = 2;
for( l=1; l <= n; l++ ){
if( m%t == s ) break;
s = t; t *= 2;
}
cout<<l;
j = m/t;
if( n%2 == l%2 ){// 逆时针
if( (j+1)%3 == 0 ) cout<<" 2 1"<<endl;
if( (j+1)%3 == 1 ) cout<<" 1 3"<<endl;
if( (j+1)%3 == 2 ) cout<<" 3 2"<<endl;
}
else{// 顺时针
if( (j+1)%3 == 0 ) cout<<" 3 1"<<endl;
if( (j+1)%3 == 1 ) cout<<" 1 2"<<endl;
if( (j+1)%3 == 2 ) cout<<" 2 3"<<endl;
}
}
return 0;
}