华容道解题报告

华容道解题报告


基本思想:

广度优先遍历搜索所有可能棋局。

实现方法:

1.棋子的类型(hrd.h)
 #define CHESS_BLANK  0 //空白
 #define CHESS_G4  1 //四格棋子
 #define CHESS_G2H  2 //横向两格棋子
 #define CHESS_G2V  3 //纵向两个棋子
 #define CHESS_G1  4 //一格棋子
 #define BOUND   5 //边界
 可用3位编码表示。

2.布局的表示方法(board.h)
 typedef struct Board {
  unsigned long long id;
  char layout[9][8];
  char index[12][2];
 } *Board;

 id为布局的压缩表示方法。3位表示一个格子的状态,共需60位,使用一个64位的整数表示。gen_id()函数用于由layout数组计算id。
 layout为布局的直观表示方法。布局存储在位于中央的layout[2...6][2...5]中。周围保留宽度为2的边界,均填入BOUND类型。(便于行棋时的比较判断)。
 index中保存每一枚棋子的横纵座标的索引。共10枚棋子,加两个空格。

3.棋子的属性(board.h)
 extern int wh[12][3];
 与index对应,保存每一枚棋子的长度、宽度、和类型值。顺序为:
  0   1    2    3    4    5    6   7   8   9   10     11
  G4, G2V, G2V, G2V, G2V, G2H, G1, G1, G1, G1, BLANK, BLANK

4.采用hash表保存和查询已有的棋局id。(hash.h)
 void add_hash(unsigned long long id);
 int get_hash(unsigned long long id);

5.逆向的搜索树:每获得新的状态节点都设一个链接指向父节点。(tree.h)
 typedef struct TreeNode {
  Board board;
  struct TreeNode *parent;
 } *TNode;

6.队列用于BFS。(queue.h, 循环链表实现)
 typedef struct QueueNode {
  TNode tnode;
  struct QueueNode *next;
 } *QNode;

7.搜索:对指定棋局,搜索每一枚棋子是否有可行的移动。若有,产生移动后的棋局,检查是否是新的棋局。如果是,则加入搜索树、队列和hash表。继续下一步搜索。

优化策略:

使用棋局压缩编码进行与先前棋局的比较是提高效率的关键。我开始没有想到,是看到他人的解法才获得启示。hash表可以提供常数的查找时间,hash函数随便写了一个(hash.c),看来还可以。

棋子的移动方式要考虑周全,G4有四种可能,G2H/G2V各有六种可能,G1则有16种可能。需要合理的安排条件语句,避免不必要的开销。

这里只实现了对于标准“横刀立马”布局的搜索,没有做进一步的推广。

题目的规模并不大。Profiling显示调用开销占前三位的是gen_id(), add_hash()和get_hash()。在我的600MHzCPU上求解“横刀立马”81步解法需要0.3s左右,共搜索23822个状态节点。

------------------
源代码: hrd.tar.bz2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值