作者:郭华
花了一个星期的时间,写了华容道的程序。现在把程序拿出来和大家共享。
华容道问题用计算机求解,一般采用广度搜索的方法,其原理很简单,就是把下一步可能有的走法全部算出来,比如第一步有五种走法,将这五种走法的下一步走法分别算出来,可能会有三十步,在继续将这三十步走法的下一步走法分别算出来,可能会更多,以此类推,直到达到目标状态(曹操在出口位置)为止。
在解华容道的问题上,我觉得有两个问题比较棘手。
其一、算法的效率。
其二、获得最优解法。
我是这样解决的:
1、 要提高算法的效率,首先要知道算法的瓶颈在什么地方,在得出每一个状态(走完一步各个棋子的位置)都要和前面的状态进行比较,以保证不重复,随着步数的增多,状态数会大幅度增加,这是,和前面的状态比较这一过程成了整个算法的效率。解决的办法,从两个地方着手,其一,增加每一步比较的速度。在程序中,用5*4的数组表示一个状态,这样,每一次比较要比较二十个数,因为数组中每个数定义从0-7,用三个二进制位可以表示,3*20=60位,用一个64位数就可以表示(有的资料说用四个字节就可以,我实在想不出来),这样每次比较一个64位数就可以了。其二、减少比较的状态,这是提高效率的关键。比较的时候不要和前面所有的状态都进行比较,只要和前两步的所有状态进行比较就可以了。经过以上的优化,在解横刀立马时,大约需要一,两秒钟就可以了,(我的机器,赛扬1.1OC1.46)。
2、 获得最优解法,比如横刀立马是81步,这里的一步指移动一个棋子,可以把一个卒子向一个方向移动两格,或者卒子拐弯移动两格,或者一个将向一个方向移动两格(横将横着移,竖将竖着移)都是一步。获得最优解法的关键是把下一步可能有的走法全部算出来,不能遗漏。我是根据空格来算走法的的,分三种情况:
① 、卒子拐弯移动,如果有连着两个空格(横向的),则如果在它的上面或下面(有四个位置)有卒子的话,那么可以拐弯移动,有四种走法。如果两个空格是竖向的,那么,空格的左右如果有卒子,也可以拐弯移动,也有四种走法。
②、向一个方向移动两格,这里可能出现的情况有:卒子向一个方向移动两格,横将横着移两格,竖将竖着移两格
③、考虑向一个方向移动一格的情况,这里情况很多,我不一一列举了。
以上的算法很麻烦,很大一部分程序用来写这个了,如果大家有更简单的,可以告诉我,但一个原则,必须把所有的走法全部考虑。
另外,说一下我在写程序时的小插曲。程序快写好时,运行时发现,每解一次,内存使用会增加7,8兆,后来发现分配的内存每释放导致的,其实在函数中也就分配了几十个字节,由于被重复调用,最后泄漏的内存就很可观了,以后使用指针分配内存可要注意了,(C用malloc,C++用new),一定要释放,弄不好,^@^。
程序用dev-C++ 4.9.9.0(可以从网上下,只有十多兆)编译通过,因为dev C++没有框架等东西,所以界面直接用window API写的。生成的可执行文件很小,68 K。另外,在程序中可以自定义布局,用5*4数表示。其中0-空格,1-卒子,2到6 将,7曹操。