贪食蛇的进化之路

贪食蛇的进化之路

         POJ 1324 http://acm.pku.edu.cn/JudgeOnline/problem?id=1324

         此题是要求计算贪食蛇从一个初始位置把头移动到(0,0)位置需要最少移动的步数。

以下是我的优化过程。

Run id   user id problem result memory time language codelength   submit time

4981334 zengkui 1324 Accepted     244K 16MS   C++   5548B      2009-04-15 11:04:24
3445390 zengkui 1324 Accepted     592K 188MS G++      3546B    2008-05-22 21:24:22
3422325 zengkui 1324 Accepted     3628K 1672MS G++      3173B    2008-05-16 16:36:26
3422019 zengkui 1324 Accepted     13488K 2500MS G++    2955B    2008-05-16 15:25:00

这几次提交可以说记录我的每一次优化策略的效果。

关键字: bfs hash   位运算   A*   估价函数   队列 状态
第一次提交(3422019):这个代码里用的是最传统的BFS思路以及最简单的数据结构

对蛇的状态存储:存下蛇的头的位置,然后记录蛇身每段相对于前一段的位置进行存储。这样一个整数就能搞定

State = s * R * C + r * C + c;(s 为相对位置,(r,c)为蛇头位置)

占用的状态空间为 4^7 * 20 *20 + 20 * 20 + 20

然后就是普通的BFS了,每次从队列头取出节点。利用state算出蛇的头部以及以后每段的位置。然后向四个方向进行扩展。判重开一个很大的bool数组。

总结:这种方法是最容易想到的一种,也是最直接的方法。简单可行。但是消耗的时间多.用来判重需要的空间比较大,消耗的空间也不少。

第一次改进(3422325):对于上次提交所消耗的时间和空间很是不满意:

   空间主要是消耗:对蛇的状态进行用的bool数组。

时间主要是消耗:每次初始化这么大的数组需要的时间以及状态的扩展。

怎么降低时间和空间的消耗???

空间上那就得压缩一下,原来一个bool 8个位只能存一个状态,而我在查询时只要知道这个状态是否存在就行,所以就想到了2进制位,一位一个0/1就能表打我需要的信息了,这个在空间上节省到了第一次提交的1/8了。所以在提交后的效果是时间上优化减少了1000MS空间到了1/4.

         在空间上其实还有一个改进。其实在队列上也用了不少空间。所以可以采用循环队列来处理,这样空间能用的更少。只是我没有这么写。

   总结:在这一步优化当中没有减少对状态的判断以及存储。那么要在时间和空间上有一个质的飞跃就需要减少对状态的扩展——这才是减少空间和时间的关键所在。

第二次改进(3445390):其实第一次改进,只是利用了一些小的技巧。在算法本质上没有什么改进。要想把时间有一个质的飞跃,就必须在算法上有一个很好的优化。我记得应该是在第一次优化后的第2天,记得还是在晚上睡觉前刷牙的时候,大脑灵光一现想到了一个比较好的优化方法。A star。

     用到Astar 那么首先想到的是估价函数,因为同样的一个问题可能存在着很多估价函数,而且在收敛效果上也存在这很大的差别,所以能选择一个好的估价函数也能给解题带来不错的效果。我这里采用的是:利用一次BFS 计算出(0,0)到各个点的距离,这个距离乘以10 作为我的股价函数。为什么要乘以10呢?这里就是为了扩大我对估计值的影响,更快的向结果收敛,从而减少对状态的扩展。

实践证明这个函数的效果还是不错的。

这一次对蛇的存储也做了些改变,完全利用位运算。

题目范围是20x20 那么存在蛇头位置需要10 bit 而还有7段蛇身又需要14bit。蛇走过的步数用另外一个int存下来。

去重策略,为了简化代码的书写,我直接用了stl里的set来进行状态去重。

众所周知用到Astar就需要一个高级的点的队列——优先队列。同样也是为了代码的书写方便我直接用了stl的priority_queue。。。。。。。stl真是太好用了。

在进行了上述处理后,发现时间上确实有了实质性的改变,缩小到了188MS。

做到这里,其实我知道时间上还存在优化空间,因为这个程序里有两个耗时的东东存在一个set 一个queue。Stl——耗时的魔鬼啊。

优化总结:A* 的实质是减少了状态的扩展,从而在时间和空间上有了较大的优化

第三次改进:这个改进距离上次改进有一年的时间差,最近又有人提起了这题。想想还是继续优化下吧。

   改进点1:自己用c++实现了一个优先队列的模版。

   改进点2:利用位存储来进行hash对状态判重。

改进后的效果变成了244K 16MS

总结:没有最好,只有更好

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值