HDOJ-2175 汉诺塔IX

题目大意:基于汉诺塔原型,第一根柱子上有n个盘子,从上至下编号从1依次递增至n。在最佳移动方案中,第m次所移动的盘子的编号。

解题思路:模拟必然是会超时的。但根据汉诺塔的递归原理,容易发现,对于n阶汉诺塔,将第一个盘从A柱移动到B柱是一步,将前两个盘从A柱移动到B柱是3步,以此类推,将n个盘从A柱移动到B柱的步数是2^n-1步。而第m步必然在以上递推的值所划分出来的区间之中。查找到区间i后,可以发现,我们把问题缩小为求n-i阶汉诺塔的第m-(used[i]+1)步。同时,如果发现第m步正好是i阶汉诺塔移动后的下一步,那必然是移动i+1号盘子,若正好是i阶汉诺塔移动的步数,那就必然是1号盘子,这就是递归的边界了。

每一阶所需的步数可以用公式快速得出并预缓存,相对于模拟,这种区间查找,缩小范围的方法极大地降低了时间复杂度。

 1 #include <iostream>
 2 using namespace std;
 3 long long int cache[66];
 4 int flag=1;
 5 void find(long long int m)
 6 {
 7     int i;
 8     for(i=1;i<=65;i++)
 9     {
10         if(cache[i]==m)
11         {
12             flag=1;
13             return;
14         }
15         if(cache[i]<m&&m<cache[i+1])
16         {
17             if((cache[i]+1)==m)
18             {
19                 flag=i+1;
20                 return;
21             }
22             else
23             {
24                 find(m-(cache[i]+1));
25             }
26         }
27     }
28 }
29 int main() {
30     int i;
31     cache[1]=1;
32     for(i=2;i<=65;i++)
33     {
34         cache[i]=cache[i-1]*2+1;
35     }
36     long long int n,m;
37     while(cin>>n>>m)
38     {
39         if(n==0&&m==0)
40             break;
41         flag=1;
42         find(m);
43         cout<<flag<<endl;
44     }
45         return 0;
46 }

 

posted @ 2016-03-26 11:15  Luke_Ye  阅读(378)  评论(0编辑  收藏  举报