分支限界法

316 阅读2分钟

类似于回溯法,也是一种在问题的解空间树T上搜索问题解的算法。但在一般情况下,分支限界法与回溯法的求解目标不同。回溯法的求解目标是找出T中满足约束条件的所有解,而分支限界法的求解目标则是找出满足约束条件的一个解,或是在满足约束条件的解中找出使某一目标函数值达到极大或极小的解,即在某种意义下的最优解。

所谓“分支”就是采用广度优先的策略,依次搜索E-结点的所有分支,也就是所有相邻结点,抛弃不满足约束条件的结点,其余结点加入活结点表。然后从表中选择一个结点作为下一个E-结点,继续搜索。

[1] 选取节点

  1. FIFO搜索
  2. LIFO搜索
  3. 优先队列式搜索

[2] 布线问题

印刷电路板将布线区域划分成n×n个方格阵列,布线问题要求确定连接方格a到方格b的最短布线方案;布线时,电路只能沿着直线或直角(方格)布线;已经布线的方格被锁定,即不允许其它线路穿过

#!/usr/local/anaconda3/bin/python
from queue import Queue 
"""
- 分支界限法
- 广度优先搜索
- 布线问题
"""

from operator import eq


def find_path(grid, start, end):
    if eq(start, end):
        return [start]
    # offset 各个方向上的偏移量
    # 对应  上, 右, 下, 左
    offset = [[0, 1], [1, 0], [0, -1], [-1, 0]]
    """
    cur 当前位置
    next 下一个位置
    dir_num 方向数目
    q 储存展开位置
    path 起点到终点的路径
    """
    cur, q, dir_num, next, path = start, Queue(), 4, [0, 0], []
    grid[start[0]][start[1]] = 2
    while True:
        for i in range(dir_num):
            next[0] = cur[0] + offset[i][0]
            next[1] = cur[1] + offset[i][1]
            if grid[next[0]][next[1]] == 0:
                grid[next[0]][next[1]] = grid[cur[0]][cur[1]] + 1
                if eq(next, end): break
                q.put(next[:])
        if eq(next, end): break
        if q.empty(): return path
        cur = q.get()
    path_len = grid[end[0]][end[1]] - 2
    cur = end
    for j in range(path_len - 1, -1, -1):
        path.append(cur)
        for i in range(dir_num):
            next[0] = cur[0] + offset[i][0]
            next[1] = cur[1] + offset[i][1]
            if grid[next[0]][next[1]] == j + 2: break
        cur = next
    path.append(start)
    path.reverse()
    return path
   
if __name__ == '__main__':
    start = [3, 2]
    end = [4, 6]
    grid = [
        [1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 0, 0, 1, 0, 0, 0, 0, 1],
        [1, 0, 0, 1, 1, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 1, 0, 0, 1],
        [1, 0, 0, 0, 1, 1, 0, 0, 1],
        [1, 1, 0, 0, 0, 1, 0, 0, 1],
        [1, 1, 1, 1, 0, 0, 0, 0, 1],
        [1, 1, 1, 1, 0, 0, 0, 0, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1]
    ]
    print(find_path(grid, start, end))