Chinaunix首页 | 论坛 | 博客
  • 博客访问: 958923
  • 博文数量: 33
  • 博客积分: 803
  • 博客等级: 军士长
  • 技术积分: 1755
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-05 18:58
个人简介

《Python科学计算》的作者

文章分类

全部博文(33)

文章存档

2016年(1)

2014年(2)

2013年(3)

2012年(27)

分类: Python/Ruby

2012-02-22 20:32:04

迷宫难题
maze_2011_2012.png

从左边入口处的“2011”进去,在迷宫里转悠,最后变为“2012”从右边出来。你可以在迷宫里随便转圈,可以重复之前走过的路,但不能直接退回上一次刚刚走过的路。每经过一条路时都需要按照路上的标示立即进行计算。

思考解题方案

这是一个广度搜索问题。由于同一条路不能连续走两回,因此已搜索过的状态节点包括三个信息:

  • 当前位置:2011处的位置编号为0, 中间处的位置编号为1, 2012处的编号为2。
  • 当前的数值。
  • 上一步走过的路径。 注意 这个信息容易忽略,若忽略则不能得到正确解答。

从初始状态(0, 2011, “*”)开始,搜索状态(2, 2012, “3”)或(2, 2012, “5”)。其中”*”表示起点。每个状态节点都有几个相邻的状态,例如对于初始状态来说,如果走”+7”路径就到达状态(1,2018,”7”)。由于2011是一个奇数,我们不选择”/2”这条路径。

所谓广度搜索就是将所有与当前状态相邻的状态都放进一个队列中,然后从队列取出下一个状态,并重复上述步骤,直到找到目标状态。为了在搜索到目标状态时,能输出从起点状态开始所走过的路径,队列中的状态会将整个路径保存在起来。

程序
from collections import deque

def solve(from_, to_):
    queue = deque([(0, from_, "*")])
    visited = set([])

    def next_value(pos, value):
        if pos == 0: # 在左边位置时
            yield 1, value+7, "7"
            if value % 2==0: # 只有当前的值为偶数时才选择除以2这条路
                yield 1, value//2, "2"
        if pos == 1: # 在中间位置时
            yield 0, value+7, "7"
            if value % 2==0:
                yield 0, value//2, "2"
            yield 2, value*3, "3"
            yield 2, value-5, "5"
        if pos == 2: # 在右边位置时
            yield 1, value*3, "3"
            yield 1, value-5, "5"

    while True:
        pos, value, path = queue.popleft()
        last = path[-1] # 最后走过的路径
        visit = (pos, value, last)
        if visit in visited: continue
        visited.add(visit)
        for p, v, n in next_value(pos, value):
            if n != last:
                if p == 2 and v == to_: # 如果右边位置,并且值为目标值则返回路径
                    return path + n
                queue.append((p, v, path+n))

path = solve(2011, 2012)

程序采用deque队列保存待搜索的状态节点,一开始只包含初始状态。为了加快搜索速度,我们使用一个visited集合保存所有访问过的状态节点。每访问一个状态节点,就将(位置, 数值, 最后走过的路径)存放到visited集合之中。如果从队列中取出的状态已经在visited集合中,就没有必要对其进行展开了。将展开过一次的状态保存到visited集合中。

next_value(pos, value)返回在pos位置,值为value时所有可能走的路径,其中包括上一次走过的路径。因此需要判断是否和上一次走的路径相同。

程序的输出为:

*7272753272735272753532753275

deque简介

在Python中,列表是一个动态的数组,在其尾部添加或删除元素的时间复杂度都是常数,但是在头部添加或删除元素则需要移动列表中所有的元素,因此时间复杂度为O(n)。显然列表只适合作为栈而不适合作为队列。deque是一个双向链表结构,从头部和尾部添加或删除元素的时间复杂度都为常数,但是访问某个下标的元素需要遍历链表,因此访问元素的时间复杂度为O(n)。

阅读(2920) | 评论(1) | 转发(1) |
0

上一篇:浮点数的精度

下一篇:数字路线迷宫

给主人留下些什么吧!~~

xuweihua_cu2012-02-23 14:17:05

谢谢博主,看后有收获。
1.认识了广度搜索,有例子好理解
2.因为用list就可以解决问题,所以不知道python里有专门的链表数据结构,实际上是很有用的。我要去关注一下collection模块了。