汉诺塔IV
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4635 Accepted Submission(s): 3397
Problem Description 还记得汉诺塔III吗?他的规则是这样的:不允许直接从最左(右)边移到最右(左)边(每次移动一定是移到中间杆或从中间移出),也不允许大盘放到小盘的上面。xhd在想如果我们允许最大的盘子放到最上面会怎么样呢?(只允许最大的放在最上面)当然最后需要的结果是盘子从小到大排在最右边。
Input 输入数据的第一行是一个数据T,表示有T组数据。
每组数据有一个正整数n(1 <= n <= 20),表示有n个盘子。
Output 对于每组输入数据,最少需要的摆放次数。
Sample Input
2 1 10
Sample Output
2 19684
Author xhd
Source
ACM程序设计期末考试_热身赛(感谢 xhd & 8600) 题目分析:又是一道经典汉诺塔的变种,也就是最大的可以放在堆的最上端,而且最左侧不能直接挪到最右侧。所以有两种移动方式,一种是从边侧挪向中间的杆,还有一种是边侧挪向边侧,收先设g(x)为x个盘子从中间和边侧中间挪动需要的步数,那么还是利用子问题的考虑方法,先将n-1个盘子挪到最右侧,然后将大盘子挪到中间,再将n-1个盘子挪到中间,这样任务就完成了,得到g(n) = 3*g(n-1)+2,那么下面我们再看f(n),也就是将n个盘子从最左侧挪到最右侧需要的步数,首先将n-1个挪到中间,然后最大的盘子挪到中间再挪到最右侧,然后n-1个盘子也挪到最右侧,得到f(n) = 2*g(n-1)+2,那么此题得解
代码真是简单的幼儿园小孩都1A啊
#include <cstdio>
#define MAX 22
using namespace std;
typedef long long LL;
int t,n;
LL f[MAX],g[MAX];
int main ( )
{
g[1] = 1 , g[0] = 0 , f[1] = 2;
for ( int i = 2 ; i < MAX ; i++ )
g[i] = 3*g[i-1] + 1;
scanf ( "%d" , &t );
while ( t-- )
{
scanf ( "%d" , &n );
printf ( "%lld\n" , 2*g[n-1]+2 );
}
}