PrepStack · Markdown HTML

约束满足回溯

回溯与约束搜索 · HTML

数学 / 逻辑形态

dfs(partial_assignment):若完整则输出;选择未赋值变量 x,遍历 domain(x) 中与当前约束一致的 v,apply(x=v),传播/递归,再 undo。

识别信号

容易误判的相似信号

SignalWhy it is different
只求图上的连通/最短路状态可按节点复用时应 BFS/Dijkstra,而非枚举整条历史。
约束图具有可利用的 DP 结构链、树或小树宽可用 DP,避免重复搜索等价部分赋值。
只要存在性且可化为匹配/2-SAT专门多项式算法比通用回溯更可靠。

核心不变量

进入递归时 partial assignment 满足所有已激活约束,辅助集合/计数与赋值完全同步;被剪分支不可能扩展为合法完整解。

状态、转移与处理顺序

ItemDefinition
State部分赋值、未赋值变量、每类约束的增量摘要与可选 domain。
Transition选择一个变量,尝试兼容值,原子地更新赋值与约束,递归后精确回滚。
Frontier / order搜索树中的一个一致部分赋值;优先扩展候选最少的变量可更早失败。

Python 骨架

def color_graph(graph, color_count):
    n = len(graph)
    color = [-1] * n
    def dfs(done):
        if done == n: return True
        candidates = [u for u in range(n) if color[u] < 0]
        u = max(candidates, key=lambda x: sum(color[v] >= 0 for v in graph[x]))
        forbidden = {color[v] for v in graph[u] if color[v] >= 0}
        for c in range(color_count):
            if c in forbidden: continue
            color[u] = c
            if dfs(done + 1): return True
            color[u] = -1
        return False
    return color if dfs(0) else None

正确性思路

  1. 不变量使每个被尝试的部分赋值合法。
  2. 对所选变量遍历所有当前合法值;任何完整解必给它其中一个值,所以不会漏解。
  3. 只有立即违反约束或所有候选失败时返回失败;回滚恢复父状态,故找到的完整赋值合法且失败结论可靠。

复杂度

TimeSpaceParameters
最坏 O(d^n·check),剪枝影响实际规模但不改变指数最坏界O(n+constraint_state)n 为变量数,d 为最大域大小。

边界条件

错误模式

PatternWhy it fails / fix
到叶子才检查约束保留大量必败前缀;应在 apply 后立即验证/传播。
回滚不完整赋值撤销但集合/计数未撤销会污染兄弟分支;更新应成对封装。
剪枝只是经验判断每个 prune 必须证明该前缀不可能完成,否则会漏解。
盲目按输入顺序选变量正确但可能极慢;MRV/最受限启发式通常更早暴露矛盾。

选择与排除规则

相关模板

RelationTemplateBoundary
compositionTrie 前缀树字符串路径搜索可用 Trie 前缀批量剪枝。

原创微型例子

环节内容
Result搜索证明无解,无需枚举 2³ 个完整赋值后才检查。
Setup三角形三个顶点用两种颜色,邻点颜色不同。
Trace前两点被迫异色,第三点的两个颜色都与某邻点冲突,立即回退。

Recall prompts

我的补充