您的位置:首页 > 其它

洛谷 P1242 新汉诺塔

2018-02-01 15:31 691 查看
有一句话说的好:“把大象装进冰箱,永远只要3步。”

对于汉诺塔(举个例子),想要将编号为5盘从A移到C,显然编号小于5的盘既不能在C也不能在A(不能挡路),所以它们必须在B上。

有以上一点可知道:要将K从X移动到Y上,其最少次数的操作中必须有一部分操作是为了必须将编号小于K的盘子移动到Z上

那么我们要将编号小于K的盘子从X移到Y上(经典汉诺塔),有以下几个操作:

1.将编号小于K的盘子全部移动到Z上

2.将K移动到Y上

3.将编号小于K的盘子移动到Y上

不过这道题改了一下……

很显然的是,对于给定的盘K,如果K已经在它自己的位子上了,那么不要动他(如果能)显然是最优的,而且它不会影响到编号小于K的任何操作

那么,我们用数组now[K]记录盘子K当前所处的柱子(1,2,3),用数组dest[k]记录盘子K的目标柱子(最终目标)

然后按编号从大到小枚举K,如果now[K] = dest[K],显然它就不要动了,大家当他不存在就好

可是如果我们碰到了需要编号的K盘怎么办

那么我们应该先将编号小于K的盘子移动到第三根柱子上,再将K移过去,于是编号小于K的盘子就留在第三根柱子上,而K完成了它的目标,就可以认为K不存在,继续枚举K-1了。

于是,当K的1的时候,大家都可以看作不存在了,于是达到了目标,天下大同

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int cur[50], tar[50], total, other[4][4];
int cnt = 0;
void init(void)
{
other[1][2] = 3, other[1][3] = 2;//记录第三根柱子
other[2][1] = 3, other[2][3] = 1;
other[3][1] = 2, other[3][2] = 1;
}
void hnoi(int num, int to)//经典汉诺塔,用来把所有无关的盘子移到第三根柱子上
{
if (num <= 0)return;
if (cur[num] == to) {
hnoi(num - 1, to);
return;
}
hnoi(num - 1, other[cur[num]][to]);//递归调用
cout << "move" << " " << num << " " << "from" << " " << (char)(cur[num] - 1 + 'A') << " " << "to" << " " << (char)(to - 1 + 'A') << endl;
cur[num] = to; cnt++;
hnoi(num - 1, to);
}
void move(int num, int to)//本题中要的搬盘子操作
{
if (num <= 0)return;
if (cur[num] == to) {
//move(num - 1, tar[num - 1]);//原题解中有这个步骤,但是个人认为根据本题的意思似乎不需要,而洛谷的数据也确实不需要
//hnoi(num - 1, to);
return;
}
hnoi(num - 1, other[cur[num]][to]);//如果要搬当前盘子,则要把小盘子都搬到第三个柱子上去
cout << "move" << " " << num << " " << "from" << " " << (char)(cur[num] - 1 + 'A') << " " << "to" << " " << (char)(to - 1 + 'A') << endl;
cur[num] = to; cnt++;
}
int main()
{
cin >> total; int i, j, k;
for (i = 1; i <= 3; i++) {
cin >> j;
for (k = 1; k <= j; k++) {
int t; cin >> t;
cur[t] = i;
}
}
for (i = 1; i <= 3; i++) {
cin >> j;
for (k = 1; k <= j; k++) {
int t; cin >> t;
tar[t] = i;
}
}
init();
for (i = total; i > 0; i--) {
if (cur[i] != tar[i])
move(i, tar[i]);
}
cout << cnt << endl;

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  递归