有关汉诺塔的一些问题

主要是在做题中遇到的三柱汉诺塔及四柱汉诺塔问题得到的一些见解,记录下来。(如有理解不对的地方请多多包涵)

(参考了大佬的代码)

https://blog.csdn.net/garfielder007/article/details/50537202

一、三柱汉诺塔

A、         B、      C

源位置、缓存、目的位置

算法:

(1)将A上n-1个盘以C为缓存,全部转移到B柱上。   T(n-1)

(2)将A上第n个盘直接转移到C柱上。    T(1)                  

(3)将B上n-1个盘以A为缓存,全部转移到C柱上。 T(n-1)递归过程

   T(n)= \begin{Bmatrix} & 1 & n=1\\ & 2*T(n-1)+1 & n>1 \end{matrix}

 代码:

(1)需要输出具体过程(递归)

#include <stdio.h>
void hanoi(int n,char x,char y,char z){
    if (n==1) {
        printf("%c-->%c\n",x,z);
        return;
    }
    hanoi(n-1, x, z, y);
    printf("%c-->%c\n",x,z);
    hanoi(n-1, y, x, z);
}
int main()
{
    int n;
    scanf("%d",&n);    //输入盘的个数
    hanoi(n, 'A', 'B', 'C');
}

(2)直接输出次数(迭代)

#include <stdio.h>
#define MAX 60
int main()
{
    int n,i;
    int a[MAX]={0};
    //通常习惯提前计算出结果而不是在过程中进行循环,避免时间复杂度过高
    for (i=1; i<MAX; i++) {
        if (i==1) {
            a[i]=1;
        }
        else{
            a[i]=2*a[i-1]+1;
        }
    }
    while (scanf("%d",&n)!=EOF) {
        printf("%d\n",a[n]);
    }
}

二、四柱汉诺塔

A、         B、      C、     D

源位置、缓存、缓存、目的位置

算法:(并不是最优结果,而是仿照三柱的情况

(1)将A上n-2个盘以C、D为缓存,全部转移到B柱上  T(n-2)

(2)将第n-1个盘转移到C柱上.  T(1)

(3)将第n个盘转移到D柱上.     T(1)

(4)将第n-1个盘移到D柱上.     T(1)

(4)将B上n-2个盘以A、C为缓存,全部转移到D柱上. T(n-2)

   T(n)=\begin{Bmatrix} & 1 &n=1 \\ & 3&n=2 \\ & 2*T(n-2)+3 &n>=3 \end{matrix}

代码:

(1)输出过程(递归)

#include <stdio.h>
#include <math.h>
#define MAX 65
void Move(char x,char y){
    printf("%c-->%c\n",x,y);
}

void hanoi_four(int n,char a,char b,char c,char d){
    if (n==1) {
        Move(a, d);
        return;
    }
    if (n==2) {//多出了一根柱子,我采用直接借助第二根柱子来算
        Move(a, b);
        Move(a, d);
        Move(b, d);
        return;
    }
    hanoi_four(n-2, a, c, d, b);
    Move(a, c);
    Move(a, d);
    Move(c, d);
    hanoi_four(n-2, b, a, c, d);
}
int main()
{
    int n;
    scanf("%d",&n);
    hanoi_four(n, 'a', 'b', 'c', 'd');
    
}

  (2)计算次数(迭代)

#include <stdio.h>
#define MAX 65
int main()
{
    int a[MAX]={0};
    int n,i;
    for (i=1; i<MAX; i++) {
        if (i==1) {
            a[i]=1;
        }
        else if (i==2){
            a[i]=3;
        }
        else{
            a[i]=2*a[i-2]+3;
        }
    }
    
    while (scanf("%d",&n)!=EOF) {
        printf("%d\n",a[n]);
    }
}

算法2:最优算法 Frame算法

(更多了解)

http://www.cnblogs.com/fanzhidongyzby/archive/2012/07/28/2613173.html

重点:不是将情况限制在n-2范围里,而是存在r,使移动步数最少

(1)用4柱汉诺塔算法,将A上n-r的盘以C,D为缓存,全部转移到B柱上     T(n-r)

(2)用3柱汉诺塔算法,将A上剩余r个盘通过C柱转移到D柱     2^r-1

(3)用4柱汉诺塔算法,将B上n-r个盘以A,C为缓存,全部转移到D柱上. T(n-r)

   T(n)=min(2*T(n-r)+2^{_{r}}-1)

   如何确定r的取值?

type 1

根据汉诺塔的算法计算出不同r下T(n)的取值,取最小值(1<=r<=n)

type 2

根据他人已经给出的证明,直接得到

 r=\tfrac{\sqrt{8*n-1}-1}{2}

因为r是整数,向下取整

再带入T(n)计算公式

T(n)=(n- \tfrac{r^{2}-r+2}{2} )*2^{r}+1

样例:

输入n个数,输出其移动次数

input:

3

3

4

12

output:

5

9

81

代码:

#include <stdio.h>
#include <math.h>
#define MAX 65
double r_size(int n){
    int r;
    r=(sqrt(8*n+1)-1)/2;
    return r;
}

double f_size(int n){
    double r,f;
    r=r_size(n);
    f=(n-(pow(r, 2)-r+2)/2)*pow(2, r)+1;
    return f;
}
int main()
{
    int a[MAX]={0};
    int i;
    for (i=0; i<MAX; i++) {
        
        a[i]=f_size(i);
    }
    int group,num;
    scanf("%d",&group);
    while (group--) {
        scanf("%d",&num);
        printf("%d\n",a[num]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41443611/article/details/85031708