小游戏系列算法之五广度优先搜索,双向广搜,八数码,华容道

本文介绍了八数码问题及其与小游戏的关系,详细解释了广度优先搜索(BFS)的原理,并展示了如何使用BFS解决八数码问题。在遇到状态过多导致搜索效率低下的情况时,提出了双向广度优先搜索作为优化方案,附带了AS3的代码示例。
摘要由CSDN通过智能技术生成

前段时间在玩仙五前,遇上了蚩尤冢拼图这个小游戏。

其实就是八数码问题,一直想着如何才能用最少步数求解,于是就写了个程序。

Q1:什么是八数码问题?
A1:首先假定一个3*3的棋盘(如上图),分别有1,2,3……8 共计8个不同的棋子放在上面,棋盘上还残留一个空格。移动棋子的规则是:与空格横竖相邻的棋子可以移动到空格的地方。现给定棋盘一个初始状态,一个目标状态,问如何通过移动棋子让初始状态变成目标状态。

为方便表达,一个棋盘的状态可以表示成这样,0表示空格:
123
456
780
在程序中,可以用一个以为数组储存以上状态:[1,2,3,4,5,6,7,8,0]
设0的在数组中的位置为zeroPos
那么空格在期盼中的实际位置为
zeroRow = zeroPos / 3;
zeroColumn = zeroPos % 3;

那么怎么求解八数码问题呢?最先想到的也是最简单的方法便是使用广度优先搜索,因为它实行起来简单,并且得到的解一定是最优解。

Q2:什么是广度优先搜索
A2:BFS,全称是Breadth First Search,是一种盲目搜索,按字面理解就是先向横向搜索,如树的话就是先访问同级层的结点,再访问下一层。
如图:节点的顺序表示访问次序。

 

Q3:那么如何用广度优先搜索求解八数码问题呢?
A3:
其实八数码的每个状态就相当于树的一个结点。因为空各子有可能向上下左右四个方向移动,因此每个结点都有可能有四个子结点。
如图:


在实际开发中,我们可以用“队”的储存结构来储存将要访问的结点,这样可以刚好达到广度优先搜索的顺序。

我们还要主要到,在空格的移动中,有可能会出现相同的状态,因此我们需要记录访问过的状态。如果检测到某个状态是访问过的,就不再将它加入“队”里了。

 

对于已访问状态的检索,这里推荐用哈希表。因为对于一个**{1,2,3,4,...,n},它的全排列对应的康托展开的值是唯一的。

把一个整数X展开成如下形式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[2]*1!+a[1]*0! 其中,a为整数,并且0<=a[i]<i(1<=i<=n)。这个X就是康托展开的值也是哈希的键值。

对于空格,取其(9-位置)再乘以8!。
例如:
1 3 7 2 4 6 8 0 5 的哈希的键值等于:
0*0! + 0*1! + 0*2! + 2*3! + 1*4! + 1*5! + 0*6! + 3*7! + (9-8)*8! = 55596

0*0!,0*1!,其实就是第n位数的逆序数*相应的阶乘值。

private function getHashNum(arr:Array):uint {
			var spaceNum:uint = arr.indexOf(0);
			var copyArr:Array = arr.slice();
			copyArr.splice(spaceNum, 1);
			var hashNum:uint;
			for (var i:uint=0; i < copyArr.length; i++ ) {
				var backNum:uint=0;
				for (var j:uint=0; j < i; j++ ) {
					if (copyArr[j] > copyArr[i]) {
						//求解逆序数
						backNum++;
					}
				}
				hashNum += backNum * getJieCheng(i);
			}
		
			hashNum +
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值