SGU 202 The Towers of Hanoi Revisited (DFS+预处理)

来源:互联网 发布:购买软件源代码协议 编辑:程序博客网 时间:2024/05/15 03:37

题目描述:

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2338


The Towers of Hanoi Revisited

Time Limit: 5 Seconds      Memory Limit: 32768 KB      Special Judge

You all must know the puzzle named ��The Towers of Hanoi��. The puzzle has three pegs and N discsof different radii, initially all disks are located on the first peg, ordered by their radii - the largest atthe bottom, the smallest at the top. In a turn you may take the topmost disc from any peg and move itto another peg, the only rule says that you may not place the disc atop any smaller disk. The problemis 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 disksfrom peg to peg solving the puzzle for 64 discs. The legend says that when they finish, the end of theworld would come. Since it is well known that to solve the puzzle you need to make 2N - 1 moves, asmall 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. Themanuscript found in Tibet mountains says that the puzzle the monks are solving has not 3 but Mpegs. This is the problem, because when increasing the number of pegs, the number of moves needed tomove 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 thepuzzle has M pegs and provide the scenario for moving the discs.


This problem contains multiple test cases!

The first line of a multiple input is an integer N, then a blank line followed by N input blocks. Each input block is in the format indicated in the problem description. There is a blank line between input blocks.

The output format consists of N output blocks. There is a blank line between output blocks.


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 mustcontain the moves themselves. For each move print the line of the form

move <disc-radius> from <source-peg> to <target-peg>

if the disc is moved to the empty peg or

move <disc-radius> from <source-peg> to <target-peg> atop <target-top-disc-radius>

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

1

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


题目大意:

  给定N(1<= N <=64)个盘子和M(4<= M <= 65)根柱子,问把N个盘子从1号柱子移动到M号柱子所需要的最少步数,并且输出移动过程。


解题思路:

  对于整个移动的过程可以概括为如下:

先把k个盘子,通过j跟柱子移动到中间的某根柱子上,步数:f[k][j];把剩下的i-k个盘子通过剩下的j-1跟柱子移到第j跟柱上,步数:f[i-k][j-1];最后再把中间的k个盘子移到J柱上,步数:f[k][j]。  为防止重复计算,且该题状态有限(64*65),因此作为预处理将所有的状态所需最小步数求出。再通过DFS按照上述思路打印出移动步骤即可。


复杂度分析:

时间复杂度 O(n*n)
空间复杂度 O(n*n)


#include <cstdio>#include <stack>#include <cstring>#include <algorithm>#include <iostream>using namespace std;const int maxn = 70;const unsigned long long INF=0xffffffffffffffff;///定义无限大unsigned long long f[maxn][maxn]; ///f[i][j]表示i个盘,通过j个柱子,全程移动所需要的最少次数。int pre[maxn][maxn]; ///pre[i][j]表示f[i][j]的最优方案是先将最小的path[i][j]个盘移动到中间某根的柱子上int n,m;///n个盘子 m个柱子stack<int>stk[maxn];bool used[maxn];void init(){   memset(f,INF,sizeof(f));   for(int i=3;i<=65;i++)   {       f[0][i]=0;       f[1][i]=1;   }   for(int i=1;i<=64;i++)   {       f[i][3]=2*f[i-1][3]+1;       pre[i][3]=i-1;   }   for(int i=2;i<=64;i++)    for(int j=4;j<=65;j++)     for(int k=1;k<i;k++)     {       if(f[i][j]>2*f[k][j]+f[i-k][j-1])       {           f[i][j]=2*f[k][j]+f[i-k][j-1];           pre[i][j]=k;       }    }}void dfs(int nt,int mt,int scr,int des){   if(nt==1)   {       if(stk[des].size())         printf("move %d from %d to %d atop %d\n",stk[scr].top(),scr,des,stk[des].top());       else         printf("move %d from %d to %d\n",stk[scr].top(),scr,des);       stk[des].push(stk[scr].top());       stk[scr].pop();       return;   }   int peg=0;   for(int i=1;i<=m;i++)   {       if(scr!=i && des!=i && !used[i])       {           peg=i;           break;       }   }   dfs(pre[nt][mt],mt,scr,peg);   used[peg]=true;   dfs(nt-pre[nt][mt],mt-1,scr,des);   used[peg]=false;   dfs(pre[nt][mt],mt,peg,des);}int main(){   init();   int N;   cin>>N;   while(N--)   {       cin>>n>>m;       for(int i=1;i<=m;i++) while(!stk[i].empty()) stk[i].pop();       for(int i=n;i>=1;i--) stk[1].push(i);       memset(used,false,sizeof(used));       printf("%llu\n",f[n][m]);       dfs(n,m,1,m);   }   return 0;}



0 0
原创粉丝点击