使用OR-Tools CP-SAT最大化多组2D点间欧氏距离之和的实现困境及求解
OR-Tools CP-SAT最大化多组2D点间欧氏距离之和的实现困境及求解
嗨,我看了你用OR-Tools CP-SAT实现多点间欧氏距离总和最大化的代码,确实存在几个关键问题导致结果不符合预期,咱们一步步来梳理和修正:
一、代码里的核心问题分析
变量与循环范围错误
- 你定义了
number_of_points但循环里用了未定义的number_robots,这会直接引发报错; - 计算点对差异时,循环只覆盖了前2个点(
range(2)),但你要处理3个点,应该枚举所有不重复的点对(i < j),避免重复计算同一对点的距离。
- 你定义了
欧氏距离平方计算逻辑混乱
- 用
^运算符是完全错误的!在Python里这是按位异或,不是平方运算,平方应该用**2; - 变量
a_diff从未定义,应该对应你之前创建的difference列表; - 你没有累加所有点对的距离平方,反而用单个
distance_sq变量反复覆盖,目标函数应该是所有点对的(x差平方 + y差平方)之和。
- 用
约束与变量范围不合理
- 添加
AllDifferent约束过于严格:最优解可能允许部分点的x或y坐标相同(比如三个点放在矩形的三个顶点:(1,1)、(1,20)、(20,1),它们的x或y有重复,但距离总和是最大的),强制所有x或y都不同反而会让模型找不到可行解; - 变量
distance_sq的范围设置错误:3个点有3对点,每对点的最大距离平方是(20-1)²+(20-1)²=722,总和最大是3*722=2166,初始范围应该覆盖这个值。
- 添加
二、修正后的完整代码
from ortools.sat.python import cp_model model = cp_model.CpModel() distance_range = 20 number_of_points = 3 # 存储所有(x,y)点变量 points = [] for i in range(number_of_points): x_i = model.NewIntVar(1, distance_range, f'x_{i}') y_i = model.NewIntVar(1, distance_range, f'y_{i}') points.append((x_i, y_i)) # 计算所有不重复点对的距离平方并累加 # 总距离平方的最大可能值:点对数 × 单对点最大距离平方 max_total_sq = (number_of_points*(number_of_points-1)//2) * (2*(distance_range-1)**2) total_distance_sq = model.NewIntVar(0, max_total_sq, 'total_distance_sq') sum_terms = [] for i in range(number_of_points): for j in range(i+1, number_of_points): # 计算x坐标差及平方 x_diff = model.NewIntVar(-(distance_range-1), distance_range-1, f'x_diff_{i}_{j}') model.Add(x_diff == points[i][0] - points[j][0]) x_diff_sq = model.NewIntVar(0, (distance_range-1)**2, f'x_diff_sq_{i}_{j}') model.AddMultiplicationEquality(x_diff_sq, x_diff, x_diff) # 计算y坐标差及平方 y_diff = model.NewIntVar(-(distance_range-1), distance_range-1, f'y_diff_{i}_{j}') model.Add(y_diff == points[i][1] - points[j][1]) y_diff_sq = model.NewIntVar(0, (distance_range-1)**2, f'y_diff_sq_{i}_{j}') model.AddMultiplicationEquality(y_diff_sq, y_diff, y_diff) # 单对点的距离平方 pair_dist_sq = model.NewIntVar(0, 2*(distance_range-1)**2, f'pair_dist_sq_{i}_{j}') model.Add(pair_dist_sq == x_diff_sq + y_diff_sq) sum_terms.append(pair_dist_sq) # 累加所有点对的距离平方作为总目标 model.Add(total_distance_sq == sum(sum_terms)) # 设置最大化目标 model.Maximize(total_distance_sq) # 求解模型 solver = cp_model.CpSolver() status = solver.Solve(model) if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE: print("最优解点坐标:") for i in range(number_of_points): print(f"点{i}: ({solver.Value(points[i][0])}, {solver.Value(points[i][1])})") print(f"总距离平方:{solver.Value(total_distance_sq)}") else: print('未找到可行解。')
三、修正后的关键说明
- 枚举
i < j的点对,避免重复计算同一对点的距离,同时减少模型计算量; - 对每个点对单独计算距离平方,再累加得到总和作为目标函数,符合“最大化所有点间欧氏距离之和”的需求;
- 修正了变量的取值范围,确保覆盖所有可能的结果;
- 去掉了不必要的
AllDifferent约束,让模型能找到真正的最优解(比如边界顶点组合)。
备注:内容来源于stack exchange,提问作者Ken Adams




