回溯法和分支界限法解决N后问题

节点的数据结构

class Node(object):  # 节点类
    def __init__(self, header, coor, size):
        self.header = header  # 记录前一个节点
        self.coor = coor  # 当前结点的坐标 元组
        self.footer = [None for i in range(size)]  # 记录子节点

    def get_trace(self):  # 获得当前结点之前的坐标(包括当前结点)
        hd = self
        lst = list()
        while hd.header:
            lst.append(hd.coor)  # 不断向上遍历,将坐标放入list中
            hd = hd.header
        lst.reverse()  # 将坐标反转
        return lst

约束函数

def constraint(node):  # 约束函数
    lst = node.get_trace()
    length = len(lst)
    for i in range(length):  # 遍历所有坐标
        coor_a = lst[i]
        for j in range(i+1, length):
            coor_b = lst[j]
            # 1. 不在同一直线,任何两个节点的横纵坐标不能相等
            if coor_a[0] == coor_b[0] or coor_a[1] == coor_b[1]:
                return False
            # 2. 不在同一斜线,任何两点的横坐标差的绝对值不等于纵坐标差的绝对值
            abs_x = abs(coor_a[0] - coor_b[0])
            abs_y = abs(coor_a[1] - coor_b[1])
            if abs_x == abs_y:
                return False
    return True

回溯法

子集树

代码如下:

# 回溯法-子集树函数
def backtracing_subset(results, queen_n, node):
    node_x = node.coor[0]
    if node_x == queen_n:  # 如果节点的x等于queen_n,说明是叶子节点,那么显示
        results.append(node.get_trace())
    else:
        for i in range(1, queen_n + 1):
            # 生成子节点
            temp_node = Node(node, (node_x + 1, i), queen_n)
            if constraint(temp_node):
                # 满足条件就添加到当前节点上
                temp_node.header = node
                node.footer[i-1] = temp_node
                backtracing_subset(results, queen_n, temp_node)  # 递归

排列树

代码如下:

# 回溯法-排列树函数
def backtracing_arrange(results, queen_n, node):
    node_x = node.coor[0]
    if node_x == queen_n:  # 如果节点的x等于queen_n,说明是叶子节点,那么显示
        results.append(node.get_trace())
    else:
        nums = node.nums
        for y in nums:
            # 生成子节点
            temp_node = Node(node, (node_x + 1, y), queen_n - node_x)
            i = 0  # 用于表示是第几个子节点
            if constraint(temp_node):
                # 排列树
                temp_nums = copy.copy(nums)  # 复制一份nums
                temp_nums.remove(y)  # 移除用过的y坐标
                temp_node.nums = temp_nums
                # 满足条件就添加到当前节点上
                temp_node.header = node
                node.footer[i] = temp_node
                i += 1
                backtracing_arrange(results, queen_n, temp_node)  # 递归

分支界限法

子集树

代码如下:


# 分支界限法-子集树
def branch_bound_subset(results, queen_n, root):
    que = Queue()  # 无优先级的队列
    que.put(root)  # 先将(0,0)压入
    while not que.empty():
        # 从队列中取出一个节点
        current_node = que.get()
        node_x = current_node.coor[0]  # 当前结点的x坐标
        if constraint(current_node):
            if node_x == queen_n:  # 如果是叶子节点
                # 输出结果
                results.append(current_node.get_trace())
            else:  # 不是叶子节点
                # 加入queen_n个子节点到队列中
                for i in range(queen_n):
                    temp_node = Node(current_node, (node_x+1, i + 1), queen_n)  # 生成子节点,y坐标为1,2,... queen_n
                    current_node.footer[i] = temp_node
                    que.put(temp_node)  # 压入队列

排列树

代码如下:

# 分支限界法-排列树
def branch_bound_arrange(results, queen_n, root):
    que = Queue()  # 无优先级的队列
    root.nums = [i for i in range(1, queen_n+1)]  # 因为是排列树,每一层的y坐标都是不一样的,一开始有1,2,...,queen_n这几个数
    que.put(root)  # 先将(0,0)压入
    while not que.empty():
        # 从队列中取出一个节点
        current_node = que.get()
        node_x = current_node.coor[0]  # 当前结点的x坐标
        if constraint(current_node):
            if node_x == queen_n:  # 如果是叶子节点
                # 输出结果
                results.append(current_node.get_trace())
            else:  # 不是叶子节点
                # 加入子节点到队列中
                num = queen_n - node_x  # num表示当前结点的子节点有多少个
                nums = current_node.nums
                i = 0  # 用于表示是第几个子节点
                for y in nums:
                    temp_node = Node(current_node, (node_x + 1, y), num - 1)  # 用nums里的数值做为y坐标,生成一个子节点
                    temp_nums = copy.copy(nums)  # 复制一份nums
                    temp_nums.remove(y)  # 移除用过的y坐标
                    temp_node.nums = temp_nums
                    current_node.footer[i] = temp_node
                    i += 1
                    que.put(temp_node)  # 放入队列

测试函数

主函数代码

if __name__ == '__main__':
    queen_n = 4
    root = Node(None, (0, 0), queen_n)
    root.nums = [i for i in range(1, queen_n + 1)]
    results = []
    backtracing_subset(results, queen_n, root)
    # backtracing_arrange(results, queen_n, root)
    # branch_bound_subset(results, queen_n, root)
    # branch_bound_arrange(results, queen_n, root)
    for coors in results:
        print(coors)

运行结果

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值