回溯法和分支界限法解决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)
运行结果
相关文章推荐
- 回溯法解决马步遍历问题
- 回溯法解决N皇后问题
- 回溯法解决N皇后问题
- 回溯法解决N皇后问题
- php回溯法解决0-1背包问题
- 用回溯法解决背包问题
- 回溯法解决 排列组合问题 全排 选排 可重复 不可重复
- 回溯法解决马步问题
- 回溯法解决组合与数的问题(递归与非递归算法)
- 用回溯法解决0-1背包问题
- 使用回溯法来解决n皇后问题
- 0-1背包问题求解归纳(动态规划法,贪心算法,回溯法,分治法和分支界限法)__更新到完整
- 回溯法解决八皇后问题--精简版
- 回溯法解决八皇后问题---用Java语言
- 回溯法解决装载问题
- 回溯法解决“八皇后”问题
- 0-1背包问题之使用回溯法解决
- 回溯法(backtracking)解决平衡集合问题
- VC++2012编程演练数据结构《8》回溯法解决迷宫问题
- 采用openMP并行方法,实现用分支界限法解决的旅行售货员问题