算法竞赛入门经典训练指南打卡
题目链接:UVa 10795
思路
对于汉诺塔问题,首先需要做的是将大的盘子移动到目标位置
所以我们应该首先找到大的盘子进行判断,如果大的盘子在目标位置上,则不动,如果不在则要先移动大的盘子
因此首先找到最大的不在目标位置的盘子
然后如书上提供的思路算出初始局面移动到参考局面和目标局面移动到参考局面的步数之和再加1即为最终结果
具体的细节看代码注释
代码如下:
#include <iostream>
#define LL long long
#define ton(i , n) for(int i = 1 ; i <= n ; ++ i)
using namespace std ;
LL step(int *p , int k , int final){
if(k == 0)
return 0 ; //已经移动完了
if(p[k] == final)
return step(p , k - 1 , final) ; //当前的盘子已经在中转站了,移动其余比它小的盘子到中转站
return step(p , k - 1 , 6 - p[k] - final) + ((LL)1 << (k - 1)) ;
//将该盘子移动到中转站,比它小的所有盘子要先移动到其他柱子上面,它上面不可以有盘子,中转站上也不可以有比它小的盘子
//步数则是将其他盘子先移动到其他柱子上所需要的步数再加上他和其他盘子都移动到中转站的步数
}
int start[65] , finish[65] ;
int main(){
int kase = 1 , n ;
while (cin >> n && n){
ton(i , n)
cin >> start[i] ; //输入初始局面
ton(i , n)
cin >> finish[i] ; //输入目标局面
int k = n ;
while (k >= 1 && start[k] == finish[k])
k -- ; //找到需要移动的最大的盘子
LL ans = 0 ;
if(k >= 1){
int other = 6 - start[k] - finish[k] ; //找到中转站,即除了目标位置和初始位置的另一根柱子
ans = step(start , k - 1 , other) + step(finish , k - 1 , other) + 1 ; //计算结果
}
cout << "Case " << kase ++ << ": " << ans << endl ;
}
return 0 ;
}