1054. Hanoi Tower
Time limit: 1.0 second
Memory limit: 64 MB
Memory limit: 64 MB
Background
"Hanoi tower" puzzle is well known. There are 3 pegs with numbers: #1, #2 and #3.
N disks of different diameters are set on the first peg in the following order: the lower disk is set, the larger diameter it has. Your aim is to move all disks onto the second peg using the peg #3 as an auxiliary one. Following the rules within a move it's allowed to replace only one uppermost disk. Besides it's forbidden to put the disk of the bigger diameter onto the disk of the smaller one.
Distribution of disks on the pegs during the game must be assigned as sequence
D (element #
i of the sequence is equal to the number of peg where the disk #
i is placed on). For instance, game status after the third move is apparently determined by sequence
D=(3, 3, 1) (the first and the second disks are set on the third peg and the third disk is on the peg #1).
Example. Let's assume that 3 disks are set on the peg #1. Then the movement of the disks can be depicted in the following table (disks are numbered in ascending order of diameters):
Point of move | Peg #1 disks | Peg #2 disks | Peg #3 disks | sequence D |
0 | 1, 2, 3 | - | - | 1, 1, 1 |
1 | 2, 3 | 1 | - | 2, 1, 1 |
2 | 3 | 1 | 2 | 2, 3, 1 |
3 | 3 | - | 1, 2 | 3, 3, 1 |
4 | - | 3 | 1, 2 | 3, 3, 2 |
5 | 1 | 3 | 2 | 1, 3, 2 |
6 | 1 | 2, 3 | - | 1, 2, 2 |
7 | - | 1, 2, 3 | - | 2, 2, 2 |
Problem
Your aim is either to determine (using arbitrary sequence
D) the number of moves from the beginning of the game to the given position on condition of performing the optimal algorithm; or to print "−1" in the case of incorrect sequence declaration (i.e. the given position cannot be achieved performing the optimal algorithm).
Reference notes. Optimal algorithm can be specified with the following recursive procedure.
procedure Hanoi(N:integer; From, To_, Temp : integer); Begin if N>0 then begin Hanoi(N-1, From, Temp, To_); writeln (N, From, To_); Hanoi(N-1, Temp, To_, From) end End;For example, to move 5 disks it's enough to call Hanoi(5,1,2,3)
Admonition. It is obvious that during the game process simultaneous setting of disks on all the pegs (#1, #2, #3) is never repeated, thus the answer will always be unequivocal.
Input
The first line of input contains integer
N (1 ≤
N ≤ 31). The other
N successive lines contain integers
D
1,
D
2, …,
DN.
1 ≤
D
1,
D
2, …,
DN ≤ 3
.
Output
Output should contain either the number of moves, or −1.
Sample
input | output |
---|---|
3 3 3 1 | 3 |
题目中已经把汉诺塔的递归形式给出来了,然后就是可以利用这个模板做了。不过首先还是要理解了这个递归。
话说这是学递归的第一个例子。。。为毛我当时都没学呢。。。现在还不清楚。
其实大概理解还是很简单的,就是每次把n何其余的(n-1)看成两部分,每次先把(n-1)部分搬到3,然后n搬到2,然后换个角度,把3当做1来看,又是将(n-1)搬到2。所以f(n)=2*f(n-1)+1;
有公式f(n)=2^n-1;
//汉诺塔问题,主要是D序列 ,还要判断是否可以正确搬运 。。。
//递归,假设目前状态有n个盘子: 1.当第n个盘子位于第1根柱子上,此时正在把n-1个盘子从1移到3。
//此时去掉第n个盘子,将第2、3根柱子交换,到达这一状态的步数等于到达原状态的步数
//2.当第n个盘子位于第2根柱子上,此时正在把n-1个盘子从3移动到2。此时去掉第n个盘子,
//将第3、1根柱子交换,到达这一状态的步数+f[n-1]+1等于原步数 3.当第n个盘子位于第3根柱子上,此时必然无解,程序结束。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int d[40];
int res=0;
int flag;
void Hanoi(int n,int from,int tmp,int to)
{
if(n==0 || !flag)return ;
if(d[n]==from)
{
Hanoi(n-1,from,to,tmp);
}
else if(d[n]==to)
{
res+=(1<<(n-1));
Hanoi(n-1,tmp,from,to);
}
else
{
flag=0;
res=-1;
}
}
int main()
{
int n,i,j;
cin>>n;
res=0;
flag=1;
for(i=1;i<=n;i++)cin>>d[i];
Hanoi(n,1,3,2);
cout<<res<<endl;
}
//汉诺塔问题,主要是D序列 ,还要判断是否可以正确搬运 。。。
//递归,假设目前状态有n个盘子: 1.当第n个盘子位于第1根柱子上,此时正在把n-1个盘子从1移到3。
//此时去掉第n个盘子,将第2、3根柱子交换,到达这一状态的步数等于到达原状态的步数
//2.当第n个盘子位于第2根柱子上,此时正在把n-1个盘子从3移动到2。此时去掉第n个盘子,
//将第3、1根柱子交换,到达这一状态的步数+f[n-1]+1等于原步数 3.当第n个盘子位于第3根柱子上,此时必然无解,程序结束。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int d[40];
int res=0;
int flag;
void Hanoi(int n,int from,int tmp,int to)
{
if(n==0 || !flag)return ;
if(d[n]==from)
{
Hanoi(n-1,from,to,tmp);
}
else if(d[n]==to)
{
res+=(1<<(n-1));
Hanoi(n-1,tmp,from,to);
}
else
{
flag=0;
res=-1;
}
}
int main()
{
int n,i,j;
cin>>n;
res=0;
flag=1;
for(i=1;i<=n;i++)cin>>d[i];
Hanoi(n,1,3,2);
cout<<res<<endl;
}