洛谷 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;
}
对于汉诺塔(举个例子),想要将编号为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;
}
相关文章推荐
- [dfs] 洛谷 P1242 新汉诺塔
- 通往奥格瑞玛的道路(洛谷 1462)
- 洛谷P1531 I Hate It(线段树)
- 洛谷 P1525 关押罪犯==codevs 1069 关押罪犯[NOIP 2010]
- 洛谷[1090]合并果子
- 【洛谷刷题记】(1)P1110~P1119
- 洛谷P1759 通天之潜水
- 洛谷 P1414 又是毕业季II
- 洛谷P2527 [SHOI2001]Panda的烦恼
- 【NOIP2011】洛谷1313 计算系数
- 洛谷—— P1238 走迷宫
- 洛谷 P1088 火星人
- 洛谷—— P1457 城堡 The Castle
- 洛谷 P2698 [USACO12MAR]花盆Flowerpot
- 洛谷 P1131 [ZJOI2007]时态同步
- 【洛谷 1483】 序列变换
- 洛谷——P2038 无线网络发射器选址
- 洛谷 P1083 [NOIP2012 D2T2] 借教室
- 洛谷 P1522 牛的旅行 Cow Tours
- 洛谷P1218 [USACO1.5]特殊的质数肋骨 Superprime Rib