zoukankan      html  css  js  c++  java
  • 【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

    一个路径执行完毕

  • 相关阅读:
    Apache Pig使用MongoLoader产生大量空文件问题
    执行sparksql出现OOM问题
    [TD笔记]Teradata XML
    Redhat上离线/非root安装python库
    Java 多线程同步关键字synchronized各种用法/特性 总结
    CVE-2019-0708 微软远程桌面服务远程代码执行漏洞分析之补丁分析
    Spring Security 实战(使用Spring Boot项目演示)
    一些渗透中,或者扫描的nmap nse脚本推荐
    kali学习笔记(一):虚拟机安装好kali后应进行的配置
    Spring boot相关问题
  • 原文地址:https://www.cnblogs.com/alex-bn-lee/p/10714870.html
Copyright © 2011-2022 走看看