###### Acdream 1219 The Towers of Hanoi Revisited（递归汉诺塔问题）

The Towers of Hanoi Revisited
Special Judge Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)
Submit Statistic Next Problem
Problem Description

  You all must know the puzzle named "The Towers of Hanoi". The puzzle has three pegs and N discs of different radii, initially all disks are located on the first peg, ordered by their radii - the largest at the bottom, the smallest at the top. In a turn you may take the topmost disc from any peg and move it to another peg, the only rule says that you may not place the disc atop any smaller disk. The problem is to move all disks to the last peg making the smallest possible number of moves.
There is the legend that somewhere in Tibet there is a monastery where monks tirelessly move disks from peg to peg solving the puzzle for 64 discs. The legend says that when they finish, the end of the world would come. Since it is well known that to solve the puzzle you need to make 2N - 1 moves, a small calculation shows that the world seems to be a quite safe place for a while.
However, recent archeologists discoveries have shown that the things can be a bit worse. The manuscript found in Tibet mountains says that the puzzle the monks are solving has not 3 but M pegs. This is the problem, because when increasing the number of pegs, the number of moves needed to move all discs from the first peg to the last one following the rules described, decreases dramatically. Calculate how many moves one needs to move N discs from the first peg to the last one when the puzzle has M pegs and provide the scenario for moving the discs.


Input

  Input file contains N and M (1 ≤ N ≤ 64, 4 ≤ M ≤ 65).


Output

  On the first line output L - the number of moves needed to solve the puzzle. Next L lines must contain the moves themselves. For each move print the line of the form


move from to
if the disc is moved to the empty peg or
move from to atop
if the disc is moved atop some other disc.
Disc radii are integer numbers from 1 to N, pegs are numbered from 1 to M.
Sample Input

5 4
Sample Output

13
move 1 from 1 to 3
move 2 from 1 to 2
move 1 from 3 to 2 atop 2
move 3 from 1 to 4
move 4 from 1 to 3
move 3 from 4 to 3 atop 4
move 5 from 1 to 4
move 3 from 3 to 1
move 4 from 3 to 4 atop 5
move 3 from 1 to 4 atop 4
move 1 from 2 to 1
move 2 from 2 to 4 atop 3
move 1 from 1 to 4 atop 2

（1）用4柱汉诺塔算法把A柱上部分的n- r个碟子通过C柱和D柱移到B柱上【F( n- r )步】。
（2）用3柱汉诺塔经典算法把A柱上剩余的r个碟子通过C柱移到D柱上【2^r-1步】。
（3）用4柱汉诺塔算法把B柱上的n-r个碟子通过A柱和C柱移到D柱上【F(n-r)步】。
（4）依据上边规则求出所有r（1≤r≤n）情况下步数f(n)，取最小值得最终解。

F(n)=min(2*F(n-r)+2^r-1)，（1≤r≤n）。

r=((8n+1)1)/2

F(n)=(n(r2r+2)/2)2r+1
。所以算法的复杂度是
F(n)=O((2n)2(2n))
。从这这个方程中也可以看出，在n<6的时候，我们可以验证是和我们起初的构想的结构是相同的，但是当n再增多时就不是当初想的那样了。

（1）用M柱汉诺塔算法把1柱上部分的n-r个碟子通过3…M柱移到2柱上【M( n- r )步】。
（2）用M-1柱汉诺塔算法把1柱上剩余的r个碟子通过3…M-1柱移到M柱上【(r)步】。
（3）用M柱汉诺塔算法把2柱上的n-r个碟子通过1柱和3…M柱移到M柱上【M( n- r )步】。
（4）依据上边规则求出所有r（1≤r≤n）情况下步数m(n)，取最小值得最终解M(n)。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
const int MAXN = 1e2+5;
const double eps = 1e-9;
const int INF = 1e8+5;
int f[MAXN][MAXN], p[MAXN][MAXN];///f:步数 p:节点
void get(int n, int k)
{
if(f[n][k] != -1)
return;
f[n][k] = INF;
if(k < 3)
return;
for(int m=1; m<n; m++)
{
get(m, k);
get(n-m, k-1);
int tp = 2*f[m][k]+f[n-m][k-1];
if(f[n][k] > tp)
{
f[n][k] = tp;
p[n][k] = m;
}
}
}
int n, m;
int hanoi[MAXN][MAXN], num[MAXN];
void print(int s, int t, int a, int b)
{
if(a == 1)
{
printf("move %d from %d to %d ",hanoi[s][num[s]]+1,s,t);
if(num[t])
printf("atop %d",hanoi[t][num[t]]+1);
puts("");
num[t]++;
hanoi[t][num[t]]=hanoi[s][num[s]--];
return;
}
for(int i=1; i<=m; i++)
{
if(i!=s && i!=t)
{
if(hanoi[i][num[i]] > hanoi[s][num[s]-p[a][b]+1])
{
print(s, i, p[a][b], b);
print(s, t, a-p[a][b], b-1);
print(i, t, p[a][b], b);
return;
}
}
}
return ;
}
int main()
{
while(cin>>n>>m)
{
memset(f, -1, sizeof(f));
for(int i=1; i<=m; i++)
f[1][i] = 1;
get(n, m);
cout<<f[n][m]<<endl;
memset(hanoi, 0, sizeof(hanoi));
memset(num, 0, sizeof(num));
for(int i=n; i>=1; i--)
{
hanoi[1][num[1]] = i;
num[1]++;
}
for(int i=1; i<=m; i++)
hanoi[i][0] = INF;
print(1, m, n, m);
}
return 0;
}

#### 汉诺塔(Tower of Hanoi)问题的求解——利用栈与递归

2016-05-22 23:32:19

#### 汉诺塔迭代算法（Towers of Hanoi, classic problem (recursive method)）

2008-04-15 13:25:00

#### ACdream 1219 The Towers of Hanoi Revisited多柱汉诺塔【递归】

2016-05-29 22:00:07

#### c/c++ 算法之汉诺塔（河内之塔(Towers of Hanoi)）

2013-06-29 19:57:29

#### 双色汉诺塔问题

2014-09-29 22:19:22

#### 汉诺塔问题以及时间复杂度

2016-09-28 10:00:15

#### 深刻的理解递归汉诺塔（Hanoi）

2016-03-02 18:57:13

#### 汉诺塔（Hanoi）问题递归&非递归的C++实现及总结

2017-10-03 21:14:19

#### python 汉诺塔问题(Tower of Hanoi Puzzle)

2016-03-18 21:46:51

#### uva254 - Towers of Hanoi 递归

2014-01-14 11:44:44

## 不良信息举报

Acdream 1219 The Towers of Hanoi Revisited（递归汉诺塔问题）