alex_bn_lee

导航

【393】递归算法(排列组合计算,迷宫)

参考:Python 实现递归算法 - 另一个自己 - CSDN博客 

参考:一文读懂递归算法 - 我的笔记 - CSDN博客 

用递归实现以下算法:

  • Factorial
  • Hannoi Tower
  • Fibonacci
  • 迷宫

使用递归计算组合(permutation)

  • 对于一个元素的集合,直接返回值即可
  • 对于多个元素的集合
    • 遍历所有元素
    • 对于任意一个元素与其他元素合并
       

代码如下:

利用 set 可以进行简单的 + - 操作

返回结果为 迭代器,也是可以遍历的

def naive_recursive_permute(S):
    if len(S) <= 1:
        yield list(S)
    else:
        for x in S:
            for P in naive_recursive_permute(S - {x}):
                yield [x] + P
                
list(naive_recursive_permute({0}))
list(naive_recursive_permute({0, 1}))
list(naive_recursive_permute({0, 1, 2}))
list(naive_recursive_permute({0, 1, 2, 3}))

output:

[[0]]
Out[2]:
[[0, 1], [1, 0]]
Out[2]:
[[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]]
Out[2]:
[[0, 1, 2, 3],
 [0, 1, 3, 2],
 [0, 2, 1, 3],
 [0, 2, 3, 1],
 [0, 3, 1, 2],
 [0, 3, 2, 1],
 [1, 0, 2, 3],
 [1, 0, 3, 2],
 [1, 2, 0, 3],
 [1, 2, 3, 0],
 [1, 3, 0, 2],
 [1, 3, 2, 0],
 [2, 0, 1, 3],
 [2, 0, 3, 1],
 [2, 1, 0, 3],
 [2, 1, 3, 0],
 [2, 3, 0, 1],
 [2, 3, 1, 0],
 [3, 0, 1, 2],
 [3, 0, 2, 1],
 [3, 1, 0, 2],
 [3, 1, 2, 0],
 [3, 2, 0, 1],
 [3, 2, 1, 0]]

可以填写选择几个数字的排列

函数名字是组合

def combination(m_list, nb):
    if nb == 1:
        for m in m_list:
            yield [m]
    else:
        for k in range(len(m_list)):
            for i in combination(m_list[0:k]+m_list[k+1:], nb-1):
                yield [m_list[k]] + i

list(combination([1, 2, 3, 4], 1))
list(combination([1, 2, 3, 4], 2))
list(combination([1, 2, 3, 4], 3))
list(combination([1, 2, 3, 4], 4))

output:

[[1], [2], [3], [4]]
Out[52]:
[[1, 2],
 [1, 3],
 [1, 4],
 [2, 1],
 [2, 3],
 [2, 4],
 [3, 1],
 [3, 2],
 [3, 4],
 [4, 1],
 [4, 2],
 [4, 3]]
Out[52]:
[[1, 2, 3],
 [1, 2, 4],
 [1, 3, 2],
 [1, 3, 4],
 [1, 4, 2],
 [1, 4, 3],
 [2, 1, 3],
 [2, 1, 4],
 [2, 3, 1],
 [2, 3, 4],
 [2, 4, 1],
 [2, 4, 3],
 [3, 1, 2],
 [3, 1, 4],
 [3, 2, 1],
 [3, 2, 4],
 [3, 4, 1],
 [3, 4, 2],
 [4, 1, 2],
 [4, 1, 3],
 [4, 2, 1],
 [4, 2, 3],
 [4, 3, 1],
 [4, 3, 2]]
Out[52]:
[[1, 2, 3, 4],
 [1, 2, 4, 3],
 [1, 3, 2, 4],
 [1, 3, 4, 2],
 [1, 4, 2, 3],
 [1, 4, 3, 2],
 [2, 1, 3, 4],
 [2, 1, 4, 3],
 [2, 3, 1, 4],
 [2, 3, 4, 1],
 [2, 4, 1, 3],
 [2, 4, 3, 1],
 [3, 1, 2, 4],
 [3, 1, 4, 2],
 [3, 2, 1, 4],
 [3, 2, 4, 1],
 [3, 4, 1, 2],
 [3, 4, 2, 1],
 [4, 1, 2, 3],
 [4, 1, 3, 2],
 [4, 2, 1, 3],
 [4, 2, 3, 1],
 [4, 3, 1, 2],
 [4, 3, 2, 1]]

组合实现(对于 [a, a, b, c] 这种情况,可以事先处理为 [a1, a2, b, c] 进行操作,操作后在将 a1/a2 转化为 a)

def combination(m_list, nb):
    if nb == 1:
        for m in m_list:
            yield tuple([m])
    else:
        for k in range(len(m_list)):
            for i in combination(m_list[0:k]+m_list[k+1:], nb-1):
                yield tuple(sorted([m_list[k]] + list(i)))

set(list(combination([1, 2, 3, 4], 1)))
set(list(combination([1, 2, 3, 4], 2)))
set(list(combination([1, 2, 3, 4], 3)))
set(list(combination([1, 2, 3, 4], 4)))

output:

{(1,), (2,), (3,), (4,)}
Out[67]:
{(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)}
Out[67]:
{(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)}
Out[67]:
{(1, 2, 3, 4)}

迷宫(所有路径)

从某一点为起点,到达终点,利用 DFS 方法

伪代码如下:

# 首先需要定义四个方向的步长
# four directions
# up, right, down, left

item = [(-1, 0), (0, 1), (1, 0), (0, -1)]

def find_a_way(point_start, point_end):
    # 将点进栈并赋值为 False ,防止后面回来
    stack.push(point_start)
    grid[point_start] = False

    # 接下来根据两种情况进行判断
    if point_start == point_end:
        # 这就是终点了,需要输出路径,并统计数目
        stack.output()
        count += 1
    else:
        # 按照四个方向遍历
        for i in range(len(item)):
            point_tmp = (point_start[0]+item[i][0], point_start[1]+item[i][1])
            # 如果这个点是 True,就继续往下走
            if grid[point_tmp] == True:
                find_a_way(point_tmp, point_end)

    # 将进栈的数据再吐出来,并重新复制为 True
    stack.pop()
    grid[point_start] = True

首先判断上,如果可以,就卡开 find_a_way(point_tmp, point_end) 的位置,继续运行代码,然后看下一个点

如果碰巧上不可以,再看看右,如果右可以,继续卡在下一个 find_a_way(point_tmp, point_end) 的位置,此时每个点都会进栈并且标记为 False

...

以此类推,最终到达终点了,这时候进栈的数据可以打印出来了,然后运行 stack.pop() 和 grid[point_start] = True,把终点吐出来,并标记为 True

然后是返回来到 上一个 find_a_way(point_tmp, point_end) 的位置,然后继续运行下一个可行的方向,所有方向运行完以后,继续运行 stack.pop() 和 grid[point_start] = True,把这个点吐出来,并标记为 True

返回到上一点的下一个方向的时候,他又把上面的过程走了一遍。。。真的好复杂,有点乱了。。。

...

以此类推,最终退回到第一个点的 find_a_way(point_tmp, point_end) 的位置,继续运行 stack.pop() 和 grid[point_start] = True,把这个点吐出来,并标记为 True

一个路径执行完毕

posted on 2019-04-16 09:16  McDelfino  阅读(718)  评论(0编辑  收藏  举报