zoj 1217
转自
非常经典的题目 八数码问题 不能不AC的题
这道题学了不少东西 试了最土的单向BFS直接TLE 然后上网看代码 改了双向的BFS 6000ms+ 过了
关于这道题的判重也是遇到了不少困难,一开始想把状态当成1个整数,把x当成0,结果还真去写了,突然发现数组根本不能开这么大
于是想了想其实这状态总数也才 9! = 362880 就想只用这个数量的数组储存状态 把整个序列当做一个整数 我只要知道这个数在所有排列里第几个大就可以了 后来查了下这叫康托展开 转一段介绍
这里我们介绍一种可以将全排列的一种表示为“第几个排列”的方法——康托展开。
首先看几个康托展开的实例(9的全排列):
1 2 3 4 5 6 7 8 9——展开为 0。
1 2 3 4 5 6 7 9 8——展开为 1。
1 2 3 4 5 6 8 7 9——展开为 2。
由这些最开始的方法我们可以发现一个规律:从第一个数开始,依次判断判断这些数是当前没有出现过的数的第几个(由0开始),记为a1, a2, ... ,a(n - 1)。不难发现如1 2 3 4 5 6 8 7 9,由1至6都是当前没有出现过的第0个数,而8是7,8,9中的第1个(由0开始),9是7,9中的第1个,7是第0个。故a1 = a2 = ... = a6 = 0,a7 = 1,a8 = 1,a9 = 0。
之后排列数(康托展开的值)等于
a1 * (n - 1)! + a2 * (n - 2)! + ... + ak * (n - k)! + ... + an * 0!
再举几个例子:
3 5 7 4 1 2 9 6 8——展开为 98884。
5 6 7 8 1 2 3 4 9——展开为 184800。
至于双向BFS 就是知道初始和目标状态的情况下,就可以正向反向一起广搜,找到一个另一方向已搜到过的节点就得到解了
一般来讲每次选择队列中节点比较少的一边来进行下一次搜索。
双向BFS的代码
后来在网上查到了A*算法 是一种启发式搜索算法 因为这道题并不要求最优解,所以还是速度重要 空间上的开销的话 已经算出只有9!个
状态 所以可以用A*算法 启发式算法对我来说还是太复杂了 其实并搞不懂 这道题参考了网上的介绍和代码 写了一个A* 速度确实快的多
下面摘一段一个大牛对8数码问题的研究报告
启发式搜索是在路径搜索问题中很实用的搜索方式,通过设计一个好的启发式函数来计算状态的优先级,优先考虑优先级高的状态,可以提早搜索到达目标态的时间。A*是一种启发式搜索的,他的启发式函数f ' ()=g' () + h' () 能够应用到八数码问题中来。
g' () ----- 从起始状态到当前状态的实际代价g*()的估计值,g' () >= g*()
h' () ----- 从当前状态到目标状态的实际代价h*()的估计值,h' () <= h*()
注意两个限制条件:
(1)h' () <= h*() (2)任意状态的f '()值必须大于其父状态的f '()值,即f '()单调递增。
其中,g' () 是搜索的深度, h' () 则是一个估计函数,用以估计当前态到目标态可能的步数。解八数码问题时一般有两种估计函数。比较简单的是difference ( Status a, Status b ), 其返回值是a 和b状态各位置上数字不同的次数。另一种比较经典的是曼哈顿距离 manhattan ( Status a, Status b ),其返回的是各个数字从a的位置到b的位置的距离(见例子)。
例如状态 1 3 7 2 4 6 8 5 2 和状态 1 2 3 4 5 6 7 8 9 的difference 是5(不含空格)。而他的manhattan 距离是:
1 (7d一次) + 1 (2u一次) + 2 (4l两次) + 3 (6r两次u一次) + 2 (5u一次l一次) = 9
单个数字的manhattan应该小于5,因为对角的距离才4,若大于4则说明计算有误。
无论是difference还是manhattan,估计为越小越接近END,所以优先级高。
在计算difference和manhattan时,推荐都将空格忽略,因为在difference中空格可有可无,对整体搜索影响不大。
本文后面的实现将使用manhattan 不计空格的方法。其实,每移动一步,不计空格,相当于移动一个数字。如果每次移动都是完美的,即把一个数字归位,那么START态到END态的距离就是manhattan。反过来说,manhattan是START到END态的至少走的步数。
回到f '()=g' ()+ h' (),其实广度搜索是h' ()=0的一种启发式搜索的特例,而深度搜索是 f ' ()=0 的一般搜索。h' ()对于优化搜索速度有很重要的作用。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ray58750034/archive/2006/02/15/599897.aspx
我用的估计函数是Manhattan距离
下面是代码 我的代码效率太低 双向广搜和A* 都没有达到理想的效果 只是AC了1217 运行时间比大牛们用一样的算法慢很多
转自 http://blog.csdn.net/qlyzpqz/article/details/5773714
bfs 哈希