递归汉诺塔小总结

1  三根柱子普通汉诺塔

公式    2^N-1 

递推公式 p[i]=p[i-1]*2+1;

 

2 汉诺塔II  四根柱子汉诺塔 HDU1207

递推公式   p[N]=min(2*p[i]+ pow(2.0,N-i)-1)

四根柱子的汉诺塔需要这么考虑,假设有N个盘,先拿其中的i个盘到其他三根中非目标柱子上,这i个盘子的移动是四根柱子都可以使用的,假设最少的移动次数为p[i],剩下N-i个盘子移动到目标柱子上,这N-i个盘子的移动只能使用三根柱子,因为有一根柱子已经放了比这些盘子都小的i个盘子,所以与在三根柱子上移动N-i个盘子次数相等,移动次数最少为a[N-i]=pow(2.0,N-i)-1;最后把那原本的i个盘子移动到目标柱子上,这次移动可以使用四根柱子,所以移动次数依旧是p[i];所以总的最少次数为p[N]=min(2*p[i]+a[N-i]);即为:

p[N]=min(2*p[i]+ pow(2.0,N-i)-1);

代码:

#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define MAXN 0X3f3f3f3f
using namespace std;
int p[70];
void hannuo()
{
    memset(p,MAXN,sizeof(p));
    p[0]=0;
    p[1]=1;
    p[2]=3;
    for(int i=3;i<70;i++)
        {
            for(int j=1;j<i;j++)
                if(p[i]>2*p[j]+pow(2.0,i-j)-1)
                p[i]=2*p[j]+pow(2.0,i-j)-1;
        }
}
int main()
{
    hannuo();
    int x;
    while(scanf("%d",&x)!=EOF)
    {
        printf("%d\n",p[x]);
    }
    return 0;
}

3汉诺塔III HDU2064

不允许直接从最左(右)边移到最右(左)边(每次移动一定是移到中间杆或从中间移出),也不允许大盘放到下盘的上面。

递推公式:p[i]=3*p[i-1]+2;

代码:

#include <iostream>
#include<cstdio>
using namespace std;
__int64 p[40];
void hannuo()
{
    p[1]=2;
    for(int i=2;i<=38;i++)
        p[i]=3*p[i-1]+2;
}
int main()
{
   int n;
   hannuo();
   while(scanf("%d",&n)!=EOF)
   {
       printf("%I64d\n",p[n]);
   }
    return 0;
}

4 汉诺塔IV HDU 2077

不允许直接从最左(右)边移到最右(左)边(每次移动一定是移到中间杆或从中间移出),允许最大的盘子放到最上面(只允许最大的放在最上面)当然最后需要的结果是盘子从小到大排在最右边。

公式:p[n]= 3^(n-1)+ 1;

递推关系:

a[i]=3*a[i-1]+1;

p[i]= a[i-1]*2+2;

如果有n个盘子,则需要前n-1个挪到中间的盘子上,然后最大的盘子挪到最右面,需要2步,把前(n-1)个盘子从左边挪到中间是和从中间挪到右边需要相同的次数。而a数组中存放的就是那个前n-1个盘子挪动到相同位置需要的次数。结果即为a[i-1]*2+2。

而求a数组需要用到递推。公式为a[i]=3*a[i-1]+1;简化到两个盘子,小的先移动两次到最右边,大的移到中间,然后小的在移回中间,小的移动了三次,而大的移动了一次,就使他们全部挪动了一个位置。

代码:

#include<stdio.h>
int a[20]={0,1};
int main()
{
 int i,T;
 for(i=2;i<21;i++)
 {
  a[i]=3*a[i-1]+1; 
 }
 scanf("%d",&T);
 while(T--)
 {
  scanf("%d",&i);
  printf("%d\n",2*a[i-1]+2);
 }
 return 0;
}

5汉诺塔V  HDU 1995

用1,2,...,n表示n个盘子,称为1号盘,2号盘,...。号数大盘子就大,求到达目标时k号盘需要的最少移动数

找出规律,最下面的盘只需移动一次,倒数第二个盘子需要移动2次,通过p[i]=p[i-1]*2+1;

这个式子可以看出递推关系为2倍。

代码:

#include <iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,k;
        scanf("%d %d",&n,&k);
        __int64 sum=0;
        sum=pow(2.0,n-k);
        printf("%I64d\n",sum);

    }
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值