• 【递归与递推】新汉诺塔


    题目描述

    设有n个大小不等的中空圆盘,按从小到大的顺序从1到n编号。将这n个圆盘任意的迭套在三根立柱上,立柱的编号分别为A、B、C,这个状态称为初始状态。
    现在要求找到一种步数最少的移动方案,使得从初始状态转变为目标状态。
    移动时有如下要求:
        ·一次只能移一个盘;
        ·不允许把大盘移到小盘上面。

    输入

    第一行是状态中圆盘总数;
    第二到第四行分别是初始状态中A、B、C柱上圆盘的个数和从上到下每个圆盘的编号;
    第五到第七行分别是目标状态中A、B、C柱上圆盘的个数和从上到下每个圆盘的编号。

    输出

    每行一步移动方案,格式为:move I from P to Q
    最后一行输出最少的步数。

    样例输入

    6
    3 1 2 3
    2 4 5
    1 6
    0
    6 1 2 3 4 5 6
    0
    

    样例输出

    move 4 from B to C
    move 1 from A to C
    move 2 from A to B
    move 1 from C to B
    move 3 from A to C
    move 1 from B to A
    move 2 from B to C
    move 1 from A to C
    move 5 from B to A
    move 1 from C to B
    move 2 from C to A
    move 1 from B to A
    move 3 from C to B
    move 1 from A to C
    move 2 from A to B
    move 1 from C to B
    move 4 from C to A
    move 1 from B to A
    move 2 from B to C
    move 1 from A to C
    move 3 from B to A
    move 1 from C to B
    move 2 from C to A
    move 1 from B to A
    move 6 from C to B
    move 1 from A to B
    move 2 from A to C
    move 1 from B to C
    move 3 from A to B
    move 1 from C to A
    move 2 from C to B
    move 1 from A to B
    move 4 from A to C
    move 1 from B to C
    move 2 from B to A
    move 1 from C to A
    move 3 from B to C
    move 1 from A to B
    move 2 from A to C
    move 1 from B to C
    move 5 from A to B
    move 1 from C to A
    move 2 from C to B
    move 1 from A to B
    move 3 from C to A
    move 1 from B to C
    move 2 from B to A
    move 1 from C to A
    move 4 from C to B
    move 1 from A to B
    move 2 from A to C
    move 1 from B to C
    move 3 from A to B
    move 1 from C to A
    move 2 from C to B
    move 1 from A to B
    56

    解:显然该题是用递归解题。因为不允许把大圆盘放在小圆盘上,所以,可以考虑为优先移动大圆盘。假设一共有n个圆盘,那么就应当优先移动编号为n的圆盘至目标位置。那么编号n的圆盘就不会对其他小圆盘有干扰了。接下来就是将编号为n-1的圆盘移动至其目标位置。
    为了之后编写函数方便,输入时可进行加工。可将“初始状态”和“目标状态”分为两个数组a和b进行记录。a[i]即表示i号的初始位置,b[i]则为目标位置。先按照题目的输入顺序输入,一旦输入i,则在a[i]中记录
    行数并转化为柱子的,b[i]同理。为了节省存储空间,可用一个变量重复输入。
    如上述分析,从最大的n开始调用。函数需两个参数,即为需移动的圆盘编号k和要将其移动的位置t。若k的初始位置已在t上,可直接return。若没有,则先将k-1至1移动到辅助柱子上,这时就要用到循环并在循环
    中递归。循环完后,再将a[k]改为t(相当于进行移动),并输出,再将移动次数加一。

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 int n,cnt=0;                                 //全局变量cnt计次
     6 char a[46],b[46];                            //记录圆盘的初始和目标位置
     7 
     8 void move(int k,char t)
     9 {
    10     if(a[k]==t)
    11     {
    12         return;
    13     }
    14     char h;                                 //辅助柱子
    15     if((a[k]==65&&t==66)||(t==65&&a[k]==66))
    16     {
    17         h=67;
    18     }
    19     if((a[k]==65&&t==67)||(t==65&&a[k]==67))
    20     {
    21         h=66;
    22     }
    23     if((a[k]==67&&t==66)||(t==67&&a[k]==66))
    24     {
    25         h=65;
    26     }
    27     for(int i=k-1;i>=1;i--)
    28     {
    29         move(i,h);                         //递归求k-1号圆盘的移动操作
    30     }
    31     printf("move %d from %c to %c
    ",k,a[k],t);
    32     a[k]=t;
    33     cnt++;
    34 }
    35 
    36 int main()
    37 {
    38     cin>>n;
    39     int m,t;
    40     for(int i=1;i<=3;i++)
    41     {
    42         cin>>m;
    43         for(int j=1;j<=m;j++)              //记录每根柱子上的圆盘序号,并将圆盘的位置通过i转换的askll码表示
    44         {
    45             cin>>t;
    46             a[t]=i+65-1;
    47         }
    48     }
    49     for(int i=1;i<=3;i++)
    50     {
    51         cin>>m;
    52         for(int j=1;j<=m;j++)
    53         {
    54             cin>>t;
    55             b[t]=i+65-1;
    56         }
    57     }
    58     for(int i=n;i>=1;i--)
    59     {
    60         move(i,b[i]);
    61     }
    62     cout<<cnt<<endl;
    63 }


  • 相关阅读:
    fiddler教程--拦截并篡改
    string
    希尔排序(缩小增量排序)
    k-选取问题
    完善版本散列表
    c++ BST继承自二叉树
    DEDECMS与DZ论坛如何整合,DEDE网站调用DZ内容
    DEDECMS如何实现定时发布文章
    DEDECMS如何设置图片上传加水印
    DEDE如何制作不同背景的列表
  • 原文地址:https://www.cnblogs.com/SoulSecret/p/8046901.html
Copyright © 2020-2023  润新知