如何使用OR-Tools高效自动生成含可变运算符的数学解谜题目
最优实现方案:使用OR-Tools CP-SAT的条件约束
你可以用CP-SAT求解器原生支持的OnlyEnforceIf条件约束+布尔指示变量实现需求,该方案完全避免了枚举所有变量取值组合的指数级开销,也不需要循环重试生成约束,求解器会自动同时选出合法的运算符组合和变量赋值。
实现逻辑
- 为每一组需要生成约束的变量对,给每个候选运算符创建一个对应的布尔变量
- 添加
AddExactlyOne约束,保证每组变量对有且只有一个运算符被选中 - 为每个运算符对应的比较逻辑添加
OnlyEnforceIf绑定:仅当对应运算符的布尔变量为真时,该比较约束生效 - 求解时OR-Tools会同步完成运算符选择和变量赋值,输出的结果天然合法
示例代码
from ortools.sat.python import cp_model import operator from itertools import combinations # 配置项:支持的运算符、变量取值范围、变量列表 OPERATORS = [ ('<', operator.lt), ('>', operator.gt), ('=', operator.eq), ] MIN_NUM = 1 MAX_NUM = 5 VAR_NAMES = ['a', 'b', 'c', 'd'] model = cp_model.CpModel() # 1. 定义数值变量 num_vars = { name: model.NewIntVar(MIN_NUM, MAX_NUM, name) for name in VAR_NAMES } # 2. 生成所有需要加约束的变量对,这里用所有两两组合,也可以自定义规则 var_pairs = list(combinations(VAR_NAMES, 2)) # 存储运算符信息,后续生成谜题用 op_info = [] for left_name, right_name in var_pairs: left = num_vars[left_name] right = num_vars[right_name] # 为每个运算符创建布尔指示变量 op_bools = [] for op_sym, _ in OPERATORS: bool_var = model.NewBoolVar(f'op_{left_name}_{op_sym}_{right_name}') op_bools.append(bool_var) # 约束:仅选一个运算符 model.AddExactlyOne(op_bools) # 绑定运算符对应的比较约束 for op_idx, (op_sym, op_func) in enumerate(OPERATORS): model.Add(op_func(left, right)).OnlyEnforceIf(op_bools[op_idx]) op_info.append( (left_name, right_name, op_bools) ) # 求解 solver = cp_model.CpSolver() status = solver.Solve(model) if status == cp_model.OPTIMAL: # 提取变量答案 solution = {name: solver.Value(var) for name, var in num_vars.items()} # 提取生成的约束 constraints = [] for left_name, right_name, op_bools in op_info: for op_idx, (op_sym, _) in enumerate(OPERATORS): if solver.BooleanValue(op_bools[op_idx]): constraints.append(f"{left_name} {op_sym} {right_name}") break print("生成的谜题约束:", constraints) print("变量取值答案:", solution)
方案优势
- 性能开销极低:不需要枚举所有变量取值组合,开销仅和变量对数量、运算符数量线性相关,和变量取值域大小无关
- 无无效重试:求解器会同时优化运算符选择和变量赋值,输出的约束一定存在合法解
- 扩展性强:新增运算符仅需要在
OPERATORS列表加对应配置即可,无需修改核心逻辑
可选优化
如果需要保证谜题有唯一解,可在拿到首次求解结果后,添加约束禁止该解再次出现,再次求解判断是否存在第二个合法解,如果不存在则符合要求。
内容的提问来源于stack exchange,提问作者bechtold
相关产品推荐
相关产品推荐

