马牛的C#学习(第六天)-实践!用C#解决汉诺塔问题

汉诺塔问题是学习递归的一个经典问题,几乎学计算机基础时每一次讲到递归,都有提到汉诺塔问题。这个学期上数据结构的课,老师叫我们写个程序解决汉诺塔问题,用什么语言实现都可以。正好,我最近在学C#,就用C#实现一下吧,练习一下C#~
  首先我们看看汉诺塔问题的描述:
约19世纪末,在欧州的商店中出售一种智力玩具,在一块铜板上有三根杆,最左边的杆上自上而下、由小到大顺序串着由64个圆盘构成的塔。目的是将最左边杆上的盘全部移到右边的杆上,条件是一次只能移动一个盘,且不允许大盘放在小盘的上面。
 
 
我们应该用递归的思想来解决这个问题。为什么会想到递归呢?
我们由四个盘子的情况可以看到,开始先想办法将上面三个盘子移到free上(从左到右的三个柱子分别记作source free target),然后再将SOURCE上的那个最大的盘子移到TARGET上,再想办法将FREE上的三个盘子移到TARGET上。考虑5个盘子的情况,先想办法将4个盘子移到FREE上,再将最大的盘子从SOURCE移到TARGET上,再将FREE上的四个盘子移到TARGET上。以此类推,考虑N个盘子时的情况,先想办法将N-1个盘子移到FREE上,再将最大的盘子从SOURCE移到TARGET上,然后想办法将FREE上的N-1个盘子移到TARGET上。
这正好符合了递归由结果推向前提、由后往前推的思想。
我们现在来看看为什么不用由前向后推的方法。我们看看图三(共三个盘子)中的第四种情况,这时是将最小的两个盘子单独放在FREE上。再来考虑一下共四个盘子时的情况,想想可以知道,到某一步时,只有最小的两个盘子在TARGET上。共有五个盘子时,又是不同。推想可知,总盘数不同时,最小的T个盘子所单独在的位置是不同的。这样,如果用穷举法来穷举总盘数为N时的所有情况,效率太低也不易实现。
         所以要用递归!
 
先来分析一下问题,我们可以用数学归纳法的思想来考虑这个问题,先看看4个以下盘子的解决方案。
图一
图二
图三
图四
考虑问题时可以从一个盘开始,在明白已知盘数时的解决办法后,将其抽象化,考虑盘数为N时的解决方法。
可以先用递归的经典图(如下)试着写出算法,错了不怕,可以一步步修改。
C#代码如下:

using System;
using System.Collections.Generic;
using System.Text;
//?????使用SOURCE作数组下标时出现  Error 1 The name 'SOURCE' does not exist in the current context C:/Documents and Settings/Manio/My Documents/Visual Studio 2005/Projects/Hanoi/Program.cs 38 54 Hanoi
//Hanoi Tower
namespace ConsoleApplication1
{
    class Class2
    {


        static void Main(string[] args)
        {
            int a;
            Console.WriteLine("Please Input the Number in the Source");
            a = Convert.ToInt16( Console.ReadLine() );
            Console.WriteLine("Moving Strat!");
            Console.WriteLine("=======================================");
           
            //实例化Hanoi
            Hanoi myHanoi = new Hanoi(a);
           
            //输出信息
            Console.WriteLine("=======================================");
            Console.WriteLine("Moving Ended!");
            Console.WriteLine("{0} in Source", a);
            Console.WriteLine("Moved {0} Time in Total.", myHanoi.time);
            Console.WriteLine("=======================================");
            Console.WriteLine(":::::::::::::::::ABOUT:::::::::::::::::");
            Console.WriteLine("   This program is written by Manio");
            Console.WriteLine("        All Right Reserved!");
            Console.WriteLine("            2006.2.18");
            Console.WriteLine(":::::::::::::::::::::::::::::::::::::::");
            Console.WriteLine("Press any key to exit this program...");
            Console.ReadKey();
        }
    }

    public class Hanoi
    {
        public const int SOURCE = 1;
        public const int FREE = 2;
        public const int TARGET = 3;
        public int time = 0;
        int[] HanioTower = new int[4];

        public Hanoi(int SourceNumber)
        {
            this.HanoiMove(SOURCE, TARGET, SourceNumber);  //构造函数中可以调用此类中方法
        }

        public void HanoiMove(int FromWhere,int ToWhere, int n)
        {
            if (n == 1)
            {
                this.HanioTower[FromWhere]--;
                this.HanioTower[ToWhere]++;
                Console.WriteLine("{0}-->{1}", FromWhere, ToWhere);
                time++;                                    //在类中引用自身类中定义的变量时,不用this.
                return;
            }

            for (int i = 1; i <= 3; i++)
            {
                if (i != FromWhere && i != ToWhere)
                {
                    ToWhere = i;
                    break;
                }
            }

            this.HanoiMove(FromWhere,ToWhere,n-1);

            for (int i = 1; i <= 3; i++)
            {
                if (i != FromWhere && i != ToWhere)
                {
                    ToWhere = i;
                    break;
                }
            }          
            this.HanoiMove(FromWhere, ToWhere, 1);

            for (int i = 1; i <= 3; i++)
            {
                if (i != FromWhere && i != ToWhere)
                {
                    FromWhere = i;
                    break;
                }
            }
            this.HanoiMove(FromWhere, ToWhere, n - 1);

            return;
        }

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值