之前有个网友问我要华容道求解代码,时过境迁,我已经没有存本了,这几天重写了一个,但考虑到不同网友的不同语言需求,我不能每个语言写一个代码吧,这不,我直接求解了所有的局面的所有答案,存于数据库中,大家可以通过访问数据库来查询求解过程,具体的使用方式我将在如下进行阐述。
在数据库可视化工具中运行如下sql语句集,由于数据量有点大,在此写不下,我上传到了资源库中,访问链接如下
冰凌——华容道求解过程sql语句集
_id:序号,自增
_aspect:局面代号,空格、曹操、横将、竖将位置组成
_row:横将个数
_col:竖将个数
这里_aspect局面组成比较抽象,我详细描述一下,以横刀立马局面为例
这是百度出来的图,【侵删】
上图中横将一个(关羽),竖将四个(其余五虎将),故其局面代表字段的
_row=1
_col=4
现在我们按照空格、曹操、横将、竖将的寻找顺序(以格子左上角的标号为主)来表示这个局面,给这个5X4的棋盘(从左到右、从上到下)分别标号为(0-19),则有以下表示:
0 , 1 , 2 , 3
4 , 5 , 6 , 7
8 , 9 , 10,11
12,13,14,15
16,17,18,19
空格位置:17、18
曹操位置:1
横将位置:9
竖将位置:0、3、8、11
那么局面代码应该是 17、18、1、9、0、3、8、11
但是这样不好看,于是我们将大于等于10的代号转变为大写字母,规则为A=10,B=11,…
0,1,2,3
4,5,6,7
8,9,A,B
C,D,E,F
G,H,I,J
如此,局面代码_aspect=HI19038B,这就是横刀立马的代码,我们在数据库的局面表中查询一下
SELECT * FROM huarongdao.tbl_aspect where _aspect='HI19038B' and _row=1 and _col=4;
select * from tbl_solution where _id=80068;
查询结果如下:
_id _step _x _y _direction
80068 1 3 1 ↓
80068 2 4 3 ←
80068 3 2 3 ↓
80068 4 2 1 →
80068 5 2 0 →
80068 6 4 0 ↑
80068 7 4 1 ←
80068 8 2 1 ↓
80068 9 2 2 ←←
80068 10 3 2 ↗
80068 11 4 2 ↑↑
80068 12 3 1 →
80068 13 3 0 ↘
80068 14 2 0 ↓
80068 15 2 2 ←←
80068 16 2 3 ←←
80068 17 3 2 ↑
80068 18 3 3 ↑
80068 19 4 1 →→
80068 20 4 0 →→
80068 21 3 0 ↓
80068 22 2 1 ↙
80068 23 2 2 ←
80068 24 2 3 ←
80068 25 0 3 ↓↓
80068 26 0 1 →
80068 27 0 0 →
80068 28 2 0 ↑↑
80068 29 3 0 ↑↑
80068 30 2 1 ←
80068 31 0 1 ↓↓
80068 32 0 2 ←
80068 33 2 3 ↑↑
80068 34 2 2 →
80068 35 4 2 ↑↑
80068 36 4 3 ↖
80068 37 4 0 →→
80068 38 2 1 ↓
80068 39 2 0 ↓
80068 40 2 2 ←←
80068 41 0 1 ↓
80068 42 0 0 →→
80068 43 1 0 ↗
80068 44 2 0 ↑↑
80068 45 3 0 ↑↑
80068 46 3 1 ←
80068 47 3 2 ↙
80068 48 1 1 ↓
80068 49 0 2 ↙
80068 50 0 3 ←
80068 51 2 3 ↑↑
80068 52 2 1 →
80068 53 1 1 ↓
80068 54 0 1 ↓
80068 55 0 0 →
80068 56 1 0 ↑
80068 57 3 0 ↑
80068 58 4 1 ←
80068 59 2 1 ↓↓
80068 60 2 2 ←
80068 61 0 3 ↓↓
80068 62 0 2 →
80068 63 0 1 →
80068 64 1 1 →
80068 65 0 0 →
80068 66 2 0 ↑↑
80068 67 2 1 ←
80068 68 1 2 ↓↓
80068 69 0 2 ↓↓
80068 70 0 3 ←
80068 71 2 3 ↑↑
80068 72 3 2 ↗
80068 73 4 2 ↑
80068 74 4 1 →→
80068 75 4 0 →→
80068 76 2 0 ↓
80068 77 2 2 ←←
80068 78 2 3 ←←
80068 79 3 2 ↑
80068 80 4 2 ↗
80068 81 3 0 →
其中
_id与局面表中_id相对应,是外键
_step为此局面的第i步
_x为此局面第i步要移动的格子的横坐标(从0开始)
_y为此局面第i步要移动的格子的纵坐标(从0开始)
_direction为此局面第i步要移动的格子的移动方向
此为求解某局面的方法
select max(_step) from tbl_solution;
得到
max(_step)
138
select _id from tbl_solution where _step=138;
得到
_id
174309
184519
185561
185745
190051
190223
select * from tbl_aspect where _id in(select _id from tbl_solution where _step=138);
得到
_id _aspect _row _col
174309 CG4DI36B 2 3
184519 FJ6DG058 2 3
185561 GH4DI36B 2 3
185745 GH6DI058 2 3
190051 IJ4DG36B 2 3
190223 IJ6DG058 2 3
select count(*) from tbl_aspect where _id not in(select distinct _id from tbl_solution);
得到
count(*)
121145
相信大家只要熟悉sql语句就可以从中获取需要的信息,熟悉语言和数据库交互就可以运用自如,有兴趣自己实现搜索算法的同学,我这里给出伪代码,提高参考:
华容道总共10个方块,四种类型,其中1个2X2,5个1X2【分为横放竖放两种】,4个1X1,我们可以分别定义四种枚举类型,本人英文不大好,这里就用拼音代替了
//方格类型枚举
enum BlockType{
KONGDI, //空地
CAOCAO, //曹操
HENGJIANG,//横将
SHUJIANG, //竖将
XIAOBING //小兵
};
枚举移动方向
//移动方向枚举
enum Direction{
UP,
DOWN,
LEFT,
RIGHT,
UPUP,
DOWNDOWN,
LEFTLEFT,
RIGHTRIGHT,
UPLEFT,
UPRIGHT,
DOWNLEFT,
DOWNRIGHT
};
定义方格类型
//方格类
struct Block{
int x; //横坐标
int y; //纵坐标
int width; //宽度
int height; //高度
int type; //类型
};
定义局面类
//局面类
struct Aspect{
Block blocks[10]; //方格数组
Aspect *lastAspect; //上个局面
int x; //上个局面移动的方格的横坐标
int y; //上个局面移动的方格的纵坐标
int direction; //上个局面移动的方格的方向
}
广搜算法
以下伪代码仅供参考,请勿当作源码复制进编辑器中编译运行!!!
以上伪代码仅供参考,请勿当作源码复制进编辑器中编译运行!!!
以上伪代码仅供参考,请勿当作源码复制进编辑器中编译运行!!!
queue<Aspect> q; //队列q存局面
set<string> s; //集合s存局面代码,方便去重
q.push(firstAspect);//挤入初始待解局面
s.add(firstAspect.toCode());//存储局面代码,toCode方法自己实现,实现原理如上边的_aspect的形成
//开始求解
while(q.size()>0){ //队列非空
Aspect now=q.pop(); //出队并获取元素
//遍历当前局面中的所有方格
foreach(block in now.blocks){
//遍历每个方向
foreach(direction){
if(block 可以 向 direction 方向移动){
//尝试移动
Aspect next;
next.blocks=now.blocks;
next的对应block向direction移动;
next.lastAspect=now;
next.x=block.x;
next.y=block.y;
next.direction=direction;
//判断是否解决了问题,即曹操是否到达坐标[3,1]
if(next.isSuccess()){
打印过程;
return;
}
//获取形成代码
string code=next.toCode();
//该局面出现过,不做任何操作
if(s.contains(code)){
pass;
//该局面第一次出现,加入队列中,之后继续求解
}else{
q.push(next);
s.add(code);
}
}
}
}
}
打印局面无解;