您的位置:首页 > 其它

zoj 2338 The Towers of Hanoi Revisited

2016-01-20 16:46 381 查看
The Towers of Hanoi RevisitedTime 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 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.

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 must contain 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

汉诺塔问题,了解一个公式。记f
[m]为n个disc,m个peg的Hanoi问题,则有dp公式f
[m]=min{f[n-k][m-1]+2*f[k][m]}。即把上面的k个disc利用m个peg转移某个中间peg,再把下面的n-k个disc利用m-1个peg转移到目标peg,最后把上面的k个disc利用m个peg移到目标peg。dp过程记下使得f
[m]最小的g
[m]=k用于反向打印移动过程。

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

附上代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
using namespace std;

typedef unsigned long long ll;
const ll INF=999999999;
ll dp[70][70];
int pre[70][70];
int n,m;
stack<int>v[80];
bool w[80];

void move(int a,int b) //从a这根柱子移到b这跟柱子
{
if(v[b].empty()) printf("move %d from %d to %d\n",v[a].top(),a,b);
else printf("move %d from %d to %d atop %d\n",v[a].top(),a,b,v[b].top());
v[b].push(v[a].top());
v[a].pop();
return;
}

void DFS(int ct,int a,int b,int h) //ct 表示盘子个数 a,b表示柱子标号 通过h根的柱子来进行操作
{
int i,j;
if(ct==1)
{
move(a,b);
return;
}
for(i=1; i<=m; i++)
if(i!=a && i!=b && !w[i]) break;
DFS(pre[ct][h],a,i,h);
w[i]=1;
DFS(ct-pre[ct][h],a,b,h-1);
w[i]=0;
DFS(pre[ct][h],i,b,h);
}

void init()
{
int i,j,k;
for(i=1; i<=70; i++) //最少三根柱子,才可以开始移动,从这里开始记录数据
{
dp[i][3]=2*dp[i-1][3]+1;
pre[i][3]=i-1;
}
for(i=4; i<=65; i++) //柱子
{
dp[1][i]=1;
for(j=2; j<65; j++)  //盘子
{
ll t=INF;
for(k=1; k<j; k++) //先移走k个盘子到一个中间柱子,剩下j-k盘子移动到目标
{
if(t>dp[j-k][i-1]+2*dp[k][i])
{
t=dp[j-k][i-1]+2*dp[k][i];
pre[j][i]=k;
}
}
dp[j][i]=t;
}
}
}

int main()
{
int i,j,T;
init();
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
printf("%lld\n",dp
[m]);
for(i=1; i<=m; i++) while(!v[i].empty()) v[i].pop(); //初始数据为空
for(i=n; i>=1; i--) v[1].push(i);
memset(w,0,sizeof(w));
DFS(n,1,m,m);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: