基于回溯算法求解N×N棋盘最小白皇后覆盖黑棋子问题咨询
回溯算法求解最少白皇后覆盖黑棋子:候选皇后的判断与选择逻辑
嘿,针对你这个问题,咱们可以从回溯的核心逻辑、状态维护和剪枝优化这几个维度来拆解,确保能高效找到最少的皇后数量:
1. 先理清楚回溯的核心状态
首先你得在回溯过程中维护三个关键状态,这是判断的基础:
- 已选皇后列表:记录当前已经选了哪些候选位置的皇后
- 已覆盖黑棋集合:用一个哈希集或布尔数组标记哪些黑棋已经被攻击到(避免重复计算)
- 当前皇后计数:用来和当前找到的最优解对比,及时剪枝
2. 候选皇后的选择优先级(优化关键)
遍历候选皇后的时候,别傻乎乎按顺序来,优先选能覆盖更多未被覆盖黑棋的候选位置。这种贪心+回溯的结合能大幅减少递归分支,更快逼近最优解——毕竟选一个能覆盖一堆漏网黑棋的皇后,比选只能覆盖一两个的效率高多了。
3. 判断是否纳入当前候选皇后的核心规则
当你考虑某个候选皇后时,按这两步来判断:
- 第一步:先看这个皇后能覆盖的黑棋里,有没有还没被已选皇后覆盖的新目标。如果它覆盖的所有黑棋都已经被之前选的皇后搞定了,直接跳过——选它只会平白增加皇后数量,完全不符合“最少”的要求。
- 第二步:如果它能覆盖新的黑棋,那就可以尝试纳入解:
- 把它覆盖的所有未被覆盖的黑棋标记为已覆盖
- 将这个皇后加入已选列表
- 递归进入下一层,处理剩下的未被覆盖黑棋
- 回溯操作:移除这个皇后,把标记的黑棋恢复为未覆盖(回到之前的状态,尝试其他可能)
4. 必须做的剪枝操作(不然会慢到离谱)
- 如果当前用的皇后数量已经等于甚至超过了当前找到的最优解,直接停止这个分支的递归——再往下走也不可能得到更优的结果,纯浪费时间。
- 一旦所有黑棋都被覆盖了,立刻更新全局最优解(比如当前用了3个皇后,之前的最优解是5,那就把最优解改成3)。
5. 终止条件
要么是所有黑棋都被覆盖(记录当前皇后数,更新最优解),要么是所有候选皇后都遍历完了,直接返回当前的最优结果。
给你贴个伪代码示例,更直观:
# 全局最优解,初始设为候选皇后总数(最坏情况) min_required = len(candidate_queens) # 提前预处理:每个候选皇后对应的覆盖黑棋集合 queen_to_black = {pos: attacked_black_set for pos, attacked_black_set in zip(candidate_queens, precomputed_covers)} # 所有黑棋的总集合 total_black = set(all_black_pieces) def backtrack(selected, covered, count): global min_required # 剪枝:当前数量已经不优于已知最优,直接返回 if count >= min_required: return # 所有黑棋都被覆盖,更新最优解 if covered == total_black: min_required = count return # 按覆盖未被覆盖黑棋的数量从多到少排序,优先选效率高的 for queen in sorted(candidate_queens, key=lambda q: len(queen_to_black[q] - covered), reverse=True): new_covered = queen_to_black[queen] - covered if not new_covered: continue # 没有新覆盖,跳过 # 选择这个皇后,进入下一层递归 backtrack(selected + [queen], covered.union(new_covered), count + 1) # 初始调用:无皇后选中,无黑棋被覆盖,计数为0 backtrack([], set(), 0)
说白了,核心就是只选能带来新覆盖价值的候选皇后,再通过剪枝和排序优化砍掉无效分支,这样就能高效找到最少的皇后数量啦。
内容的提问来源于stack exchange,提问作者user13353974




