博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CodeVs[3145 汉诺塔游戏]
阅读量:4573 次
发布时间:2019-06-08

本文共 2368 字,大约阅读时间需要 7 分钟。

题目描述 Description

题目描述 Description

汉诺塔问题(又称为河内塔问题),是一个大家熟知的问题。在A,B,C三根柱子上,有n个不同大小的圆盘(假设半径分别为1-n吧),一开始他们都叠在我A上(如图所示),你的目标是在最少的合法移动步数内将所有盘子从A塔移动到C塔。

游戏中的每一步规则如下:

1. 每一步只允许移动一个盘子(从一根柱子最上方到另一个柱子的最上方)

2. 移动的过程中,你必须保证大的盘子不能在小的盘子上方(小的可以放在大的上面,最大盘子下面不能有任何其他大小的盘子)

 

如对于n=3的情况,一个合法的移动序列式:

1 from A to C

2 from A to B

1 from C to B

3 from A to C

1 from B to A

2 from B to C

1 from A to C

 

给出一个数n,求出最少步数的移动序列

输入描述 Input Description

一个整数n

输出描述 Output Description

第一行一个整数k,代表是最少的移动步数。

接下来k行,每行一句话,N from X to Y,表示把N号盘从X柱移动到Y柱。X,Y属于{A,B,C}

样例输入 Sample Input

3

样例输出 Sample Output

7

1 from A to C

2 from A to B

1 from C to B

3 from A to C

1 from B to A

2 from B to C

1 from A to C

数据范围及提示 Data Size & Hint

n<=10

 

题解:

 

在纸上画,发现基本规律:

  • 目标一定,最短路径有且只有一条。
  • 如果要把A中n个圆盘移动到C,必须把A中最下面的移动到C。要实现这一步,前一步必须是:A只剩最后一个元素,B中为A的前n-1个元素, C为空。

百度百科:汉诺塔

可以找到

关于步数的函数:  1                       n =1

f(n)

              2 x f(n-1) - 1     n>=1

(理解汉诺塔的递归原理后,很容易得到这样的结论):

 

画图分析:

 

最小递归:n=1,f(1)。

 

n=2,实际是

第一步:调用f(1)先将1移动 到B//基于发现的基本规律2.

第二部:将A中最后一个元素移动到C,作为C的最里面的元素。

第三部:此时,A为空,B为1,C为2。即又要调用f(1),只是这次B为源,C为目标,A作为临时储存器。

 

n = 3,

第一步:f(2),源为A,目标C

第二步:将3从A移动到C。

第三部:f(2),源为B,目标C

 

n = n,

第一步:f(n-1),源为A,目标C

第二步:将n从A移动到C。

第三部:f(n-1),源为B,目标C

 

这样关于步数的函数显然易见。

 

针对本题输出要求,用vector保存元素来输出。

 

#include 
#include
#include
#include
#include
using namespace std;void remove(int n, vector
& src, vector
& mid, vector
& aim);int main(){ vector
a,b,c; /*标示a、b、c塔。*/ a.push_back("A"); b.push_back("B"); c.push_back("C"); / int n; cin >> n; cout << pow(2, n) - 1 << endl;//输出最小步数 /*填充塔A*/ string str; ostringstream oss; for (int i = n; i > 0; i--) { oss.str(""); oss << i; str = oss.str(); a.push_back(str); } // remove(n, a, b, c); return 0;}void remove(int n, vector
& src, vector
& mid, vector
& aim)//a 被移动者,b为储存器,c为目标。{ if (n == 1){ //此时a中只有一个元素1(不算名称a[0]),把他移动到aim string temp = src.back(); src.pop_back(); aim.push_back(temp); cout << 1 << " from " << src[0] << " to " << aim[0] << endl; } else { //将前n-1个元素 放到中间存储器中。 remove(n - 1, src, aim, mid); //将src中最后一个元素 直接移到目标底部。 string temp = src.back(); src.pop_back(); aim.push_back(temp);//把a的最后一个元素移动到c中。 cout << temp << " from " << src[0] << " to " << aim[0] << endl; //再将中间存储器中的所有元素(有n-1)个全部移到 没有目标储存器中。 remove(n - 1, mid, src, aim); }};

 

 

 

 

 

转载于:https://www.cnblogs.com/dingblog/p/4454499.html

你可能感兴趣的文章
setup elk with docker-compose
查看>>
C++ GUI Qt4学习笔记03
查看>>
Java基础回顾 —反射机制
查看>>
c# 前台js 调用后台代码
查看>>
2017-02-20 可编辑div中如何在光标位置添加内容
查看>>
$.ajax()方法详解
查看>>
jquery操作select(增加,删除,清空)
查看>>
Sublimetext3安装Emmet插件步骤
查看>>
MySQL配置参数
查看>>
全面理解Java内存模型
查看>>
存储过程
查看>>
生成器
查看>>
将一个数的每一位都取出来的方法!
查看>>
2) 十分钟学会android--建立第一个APP,执行Android程序
查看>>
面试题8:二叉树下的一个节点
查看>>
hash冲突的解决方法
查看>>
Asp.Net webconfig中使用configSections的用法
查看>>
mysql 二进制日志
查看>>
阻止putty变成inactive
查看>>
TP框架代码学习 学习记录 3.2.3
查看>>