使用Google OR-Tools CP-SAT求解器的Add_implications约束时可行解未被识别的问题排查
使用Google OR-Tools CP-SAT求解器的Add_implications约束时可行解未被识别的问题排查
我来帮你排查这个问题——你的核心问题是不兼容动物的相邻约束没有覆盖所有可能的放置情况,导致求解器允许了违反规则的解,同时你期望的合法解没有被优先(或正确)识别出来。
问题根源分析
你的adjacent_cages只定义了单向的相邻关系(比如只写了(cage_A, cage_B),没处理反向的(cage_B, cage_A)),而当前的约束逻辑存在漏洞:
- 你添加的两个
add_implication约束其实是等价的(互为逆否命题),只处理了“动物1在cage1则动物2不能在cage2”这一种场景 - 完全漏掉了“动物1在cage2则动物2不能在cage1”的情况——这恰恰是不兼容动物相邻的另一种违规场景
比如对于不兼容对(Boone, Lulu),你的代码没有约束“如果Boone在cage_B,那么Lulu不能在cage_A”,这就导致求解器可能生成Boone在B、Lulu在A的违规解,而不是你期望的合法解。
修正后的完整代码
下面是修复了约束逻辑的代码,同时优化了部分细节:
from ortools.sat.python import cp_model # Data animals = ["Lulu", "Abby", "Boone", "Kensey"] cages = ["cage_A", "cage_B", "cage_C", "cage_D"] # Incompatible pairs (cannot be next to each other) incompatible_pairs = [("Boone", "Lulu"), ("Boone", "Abby")] # Cage adjacencies (represented as unordered pairs) adjacent_cages = [("cage_A", "cage_B"), ("cage_B", "cage_C"), ("cage_C", "cage_D")] # Model model = cp_model.CpModel() # Variables x = {} for animal in animals: for cage in cages: x[(animal, cage)] = model.new_bool_var(f"x_{animal}_{cage}") # Constraints # Each animal goes into exactly one cage for animal in animals: model.add(sum(x[(animal, cage)] for cage in cages) == 1) # Each cage holds exactly one animal (4 animals + 4 cages, this is safe and strict) for cage in cages: model.add(sum(x[(animal, cage)] for animal in animals) == 1) # Adjacency constraints for incompatible pairs (cover all possible violation scenarios) for animal1, animal2 in incompatible_pairs: for cage1, cage2 in adjacent_cages: # Case 1: If animal1 is in cage1, animal2 can't be in cage2 model.add_implication(x[(animal1, cage1)], x[(animal2, cage2)].Not()) # Case 2: If animal1 is in cage2, animal2 can't be in cage1 model.add_implication(x[(animal1, cage2)], x[(animal2, cage1)].Not()) # Solve and print solution solver = cp_model.CpSolver() status = solver.Solve(model) if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE: print("Solution:") for animal in animals: for cage in cages: if solver.value(x[(animal, cage)]): print(f" {animal} assigned to {cage}") else: print("No solution found.")
关键修改说明
- 补全约束场景:新增了
Case 2的约束,确保对于每一对相邻笼子,不管哪个动物在哪个笼子,不兼容的动物都不能相邻放置。 - 严格笼子约束:把每个笼子的约束从
<=1改成==1,因为你有4只动物和4个笼子,这样更符合实际场景,也能减少求解器的搜索空间。
枚举所有可行解(可选)
如果你想查看所有合法的可行解(应该是2个),可以使用CpSolverSolutionCallback来遍历所有解:
class SolutionPrinter(cp_model.CpSolverSolutionCallback): def __init__(self, x, animals, cages): cp_model.CpSolverSolutionCallback.__init__(self) self.x = x self.animals = animals self.cages = cages self.solution_count = 0 def on_solution_callback(self): self.solution_count += 1 print(f"\nSolution {self.solution_count}:") for animal in self.animals: for cage in self.cages: if self.Value(self.x[(animal, cage)]): print(f" {animal} assigned to {cage}") # 替换原来的求解和打印代码 solver = cp_model.CpSolver() solution_printer = SolutionPrinter(x, animals, cages) status = solver.SearchForAllSolutions(model, solution_printer) print(f"\nTotal valid solutions found: {solution_printer.solution_count}")
内容来源于stack exchange




