您的位置:首页 > 其它

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

2017-01-06 17:16 447 查看

节点的数据结构

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)


运行结果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息