题目描述
给定A、B、C三根足够长的细柱,在A柱上放有2n个中间有孔的圆盘,共有n个不同的尺寸,每个尺寸都有两个相同的圆盘,注意这两个圆盘是不加区分的(下图为 n=3 的情形)。
现要将这些圆盘移到C柱上,在移动过程中可放在B柱上暂存。要求:
(1)每次只能移动一个圆盘;
(2)A、B、C三根细柱上的圆盘都要保持上小下大的顺序;
任务:设 An 为 2n 个圆盘完成上述任务所需的最少移动次数,对于输入的n,输出 An 。
输入格式
一个正整数n,表示在A柱上放有2n个圆盘
输出格式
一个正整数, 为完成上述任务所需的最少移动次数An 。
输入输出样例
输入#1: 1 __ 输出#1: 2
输入#2: 2 __ 输出#2: 6
说明
- 对于50%的数据,1 ≤ n ≤ 25
- 对于100%的数据,1 ≤ n ≤ 200
思路
本题对于普通的汉诺塔的区别是圆盘是成双出现的,根据小的只能放在大的圆盘上面,我们其实可以把两个相同的圆盘看成一个,只要在每次移动操作的时候多移动一次即可。还有就是找出移动的递推规律。总结方法如下:
- 由汉诺塔递推规律不难发现,圆盘移动次数和圆盘数的关系为:f(x) = 2*f(x-1) + move;
- 根据思路得到每次move操作移动两个相同得圆盘,move = 2;
- 当然,在记录次数的时候必须使用高精度加法和高精度乘法;
接下来就是实现了
#include <iostream>
using namespace std;
int n, len;
int count[201]={0}; //用来存次数的数组;
void gjc() //高精度乘法
{
// cout << "gjc\n";
int t;
for(int i=len; i>=1; i--) //一定要从高位到底位这样产生进位的话,也不会影响后面的运算;
{
t = count[i]*2;
if (t >= 10) {
count[i] = t%10;
count[i+1] += t/10;
}
else count[i] = t;
}
if (count[len+1] > 0) len++;//判断最高位的进位
}
void gjj() //高精度加法
{
// cout << "gjj\n";
int t;
count[1] += 2; //加2操作
for(int i=1; i<=len; i++)
{
if(count[i] >= 10) {
count[i] %= 10;
count[i+1] += 1;
}
else break;
}
if (count[len+1] > 0) len++;//判断最高位的进位
}
int main()
{
cin >> n;
count[1] = 0;
len = 1; //初始化长度为1,初始次数是0;
for(int i=1; i<=n; i++)
{
gjc();
gjj(); //先进行高精乘,再进行高精加;
}
for(int i=len; i>=1; i--) //从高到低输出每一位;
cout << count[i];
return 0;
}
蒟蒻一只,欢迎指正