四柱汉诺塔

来源:互联网 发布:武汉ui培训知乎 编辑:程序博客网 时间:2024/06/06 20:08

多柱汉诺塔可以用Frame–Stewart算法来解决。

The Frame–Stewart algorithm, giving a presumably optimal solution for four (or even more) pegs, is described below:

  • Let n be the number of disks.
  • Let r be the number of pegs.
  • Define T(n,r) to be the minimum number of moves required to transfer n disks using r pegs

The algorithm can be described recursively:

  1. For some k1 \leq k < n, transfer the top k disks to a single peg other than the start or destination pegs, taking T(k,r)moves.
  2. Without disturbing the peg that now contains the top k disks, transfer the remaining n-k disks to the destination peg, using only the remaining r-1 pegs, taking T(n-k,r-1) moves.
  3. Finally, transfer the top k disks to the destination peg, taking T(k,r) moves.

The entire process takes 2T(k,r)+T(n-k,r-1) moves. Therefore, the count k should be picked for which this quantity is minimum.

This algorithm (with the above choice for k) is presumed to be optimal, and no counterexamples are known.

4柱的可以借助3柱的来完成,5柱的借助4柱的来完成,等等。下面是从网上找来的4柱汉诺塔的分析过程。

 

四塔问题:设有A,B,C,D四个柱子(有时称塔),在A柱上有由小到大堆放的n个盘子,如图所示。

今将A柱上的盘子移动到D柱上去。可以利用B,C柱作为工作栈用,移动的规则如下:
①每次只能移动一个盘子。
②在移动的过程中,小盘子只能放到大盘子的上面。
设计并实现一个求解四塔问题的动态规划算法,并分析时间和空间复杂性。
 
算法思想:
用如下算法移动盘子(记为FourPegsHanoi):
1)、将A柱上n个盘子划分为上下两部分,下方部分共有k(1≤k≤n)个盘子,上方部分共有n - k个盘子。
2)、将A柱上面部分n–k个盘子使用FourPegsHanoi算法经过C、D柱移至B柱。
3)、将A柱剩余的k个盘子使用ThreePegsHanoi算法经过C柱移至D柱。
4)、将B柱上的n–k个盘子使用FourPegsHanoi算法经过A、C柱移至D柱。
 
ThreePegsHanoi算法如下(设三个柱子分别为A、B、C,A柱上共有k个盘子):
1)、将A柱上方k-1个盘子使用ThreePegsHanoi算法经过B柱移至C柱。
2)、将C柱上最后一个盘子直接移至C盘。
3)、将B柱上k-1个盘子使用ThreePegsHanoi算法经过A柱移至C柱。

 

算法步骤:
根据动态规划的四个步骤,求解如下:
1)、最优子结构性质:
   四柱汉诺塔问题的最优解是用最少的移动次数将A柱上的盘子全部移到D柱上。当盘子总数为i时,我们不妨设使用FourPegsHanoi的最少移动次数为f(i)。相应的ThreePegsHanoi 算法移动次数为g(k),由于g(k)=2g(k-1)+1=2k -1,当k确定时,g(k)也是不变的。
   f(i)为最优解时,其子问题f(i-k)也必为最优解。如果f(i-k)不是最优解,那么存在f’(i-k) < f(i-k)。用f’(i-k)替换f(i-k)将产生一个比f(i)更优的解。这与f(i)为最优解是矛盾的。所以本问题具有最优子结构性质。

2)、递归地定义问题的最优解: 
根据上述FourPegsHanoi算法得到最少移动次数f(i):


#include<iostream>#include<cstdio>#include<cmath>using namespace std;int main(){   double nums[100];   int n;   nums[1]=1;   nums[2]=3;      while(scanf("%d",&n)!=EOF){       for(int i = 3;i<=n;i++)      {  double min=2*nums[i-1]+pow(2.0,1)-1;      for(int j = 1;j<i;j++)    {  nums[i]=nums[j]*2+pow(2.0,i-j)-1;if(min>nums[i])min=nums[i];  }  nums[i] = min;     }    printf("%.0lf\n",nums[n]);      }}


0 0
原创粉丝点击