ACM训练题(HDU-2077)

汉诺塔IV
Time Limit: 1000/1000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 10895
Accepted Submission(s): 7532

Problem Description 还记得汉诺塔III吗?他的规则是这样的:不允许直接从最左(右)边移到最右(左)边(每次移动一定是移到中间杆或从中间移出),也不允许大盘放到小盘的上面。xhd在想如果我们允许最大的盘子放到最上面会怎么样呢?(只允许最大的放在最上面)当然最后需要的结果是盘子从小到大排在最右边。

Input
输入数据的第一行是一个数据T,表示有T组数据。
每组数据有一个正整数n(1 <= n <= 20),表示有n个盘子。

Output
对于每组输入数据,最少需要的摆放次数。

Sample Input
2
1
10

Sample Output
2
19684

Author
xhd

问题分析:
首先我们要知道在这个汉诺塔问题里,与最开始的汉诺塔有什么区别。最大的区别就是最大的一个盘可以放在最上面,还有一个区别是一次只能移动一格,不能跳跃式移动。
我们可以将问题慢慢简化,要想将n个盘子移动到最后一个格子,我们可以先将n-1个盘子移看做整体并且移动到中间的格子,再将第n个盘子也就是最大的那个盘子移动两次到达最后一个格子,最后我们再将在中间的n-1个盘子移动到最后一个格子即可。
如果我们将n个盘子分成n-1个盘子作为整体和最后一个盘子,这样的问题确实要简化很多。现在我们只看n-1个盘子,它从开头移动到了末尾,我们还是留下最后一个盘子不动,上面的n-2个盘子经过了A->B->C,接着我们移动最后一个盘子到B,我们可以记为f(n-2),再将n-2个盘子移动为C->B->A,将中间最大的那个盘子再移动到C,最后我们还要再将n-2个盘子移动到C,就是三次了,记为3*f(n-2)+2,最后加的2是最后一个盘移动的次数。
还记得我们刚才是将问题简化成了n个盘子分成n-1个盘子作为整体和最后一个盘子,所以我们最后还要移动两次最后一个盘子。
所以我们需要定义两个数组来接收数据,一个是n-1个盘子移动的总次数,一个是最终的移动次数。

AC代码如下:

#include
using namespace std;
int main()
{
 int i,j, T,n;
 long long a[30],b[30];
 cin >> T;
 while (T--)
 {
  cin >> n;
  a[1] = 2;
  for (i = 2; i < 21; i++)
  {
   a[i] = 3 * a[i - 1] + 2;
  }
  b[1] = 2;
  for (j = 2; j <= 20; j++)
  {
   b[j] = a[j - 1] + 2;
  }
  cout << b[n] << endl;
 }
 return 0;
}

你可能感兴趣的:(ACM训练题(HDU-2077))