nyoj 88 汉诺塔

        汉诺塔就是层叠递归调用的典型例子,一直是利用 A—>B  A-->C  B-->C 这样的单个步骤。

       具体来说,当盘数大于一时,不违背原则下(过程中总是大在下小的在上),A先借助B再放到C上。总是把盘数看成两个来解决问题。

       比如说,当盘数为二时,顾名思义,这个很简单只要三下即可完成。这个时候,可以这样想,如果是三个,就相当于二个完成,还有一个待完成,(注意要有把问题简化为两个盘的思想,这样是递归思想的思想实现),那么把完成的看成一个,剩下待完成的看成一个(带完成的还可以把最近要完成的看成一个,剩下的先别管),这样问题就回到了二个盘数时的第一步完成状态,然后C上的(二个看成一个)在借助B放到A上,这样第三个就可以从B放到C上,接下来又是二个了(这个是真正的二个),看基本步骤完成。当盘数是N时,也是利用这种思想,一步一步简化,递归完成。

       接下来谈一下N个盘要几次完成:

        当完成n个时设用M(n)次,那么,如上说的算法当完成n个(也就是n+1个时了)还有一个,这时需要把在C上的看成一个,借助B移动到A上(这时最后一个已到B上),当然要做M(n)次搬动了,完成后,B上的最后一个((n+1)个)搬动到C上。这时,问题又回到了n次开始,当然需要M(n)次了。这么一来就是M(n)*2次,加上最后一个的两次,总共是M(n)*2+2=M(n+1)次,好了现在是纯数学问题了,结果是M(n)=2^n-1.

方法一:

#include<iostream>
using namespace std;
long long g(int a,int b)
{
    int x,y;
    if(b==0)
    return 1;
    if(b==1)
    return 2;
    x=g(a,b/2);
    y=(long long)x*x%1000000;
    if(b%2==1)
    y=y*2%1000000;
    return (int)y;
}
int main()
{
   int n,t;
   long long m;
   cin>>n;
   while(n--)
   {
       cin>>m;
       t=g(2,m);
       cout<<t-1<<endl;
   }
   return 0;
}

方法二:

  1. #include<stdio.h> 
  2. int main() 
  3.     int i,j,k,l,m,n,s; 
  4.     scanf("%d",&s); 
  5.     while(s--) 
  6.     { 
  7.         int c=1; 
  8.         scanf("%d",&n); 
  9.         if(n>12500)//对输入的数据进行处理 
  10.         { 
  11.             if(n%100000<6) 
  12.                 n=n%10+100000; 
  13.             else n%=100000; 
  14.         } 
  15.         while(n--) 
  16.         { 
  17.             c=2*c; 
  18.             c%=1000000; 
  19.         } 
  20.         printf("%d\n",c-1); 
  21.     }return 0; 

 

方法三:

  1. #include<stdio.h> 
  2. int a[100006]; 
  3. int main() 
  4.     int s,m,i; 
  5.     a[1]=1; 
  6.     for(i=2;i<100006;i++) 
  7.     { 
  8.         a[i]=(2*a[i-1]+1)%1000000; 
  9.     } 
  10.     scanf("%d",&s); 
  11.     while(s--) 
  12.     { 
  13.         scanf("%d",&m); 
  14.         if(m>12500) 
  15.         { 
  16.             if(m%100000<6) 
  17.                 m=100000+m%10; 
  18.             else 
  19.                 m%=100000; 
  20.         } 
  21.         printf("%d\n",a[m]); 
  22.     } 
  23.     return 0; 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值