You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用OR-Tools CP-SAT最大化多组2D点间欧氏距离之和的实现困境及求解

OR-Tools CP-SAT最大化多组2D点间欧氏距离之和的实现困境及求解

嗨,我看了你用OR-Tools CP-SAT实现多点间欧氏距离总和最大化的代码,确实存在几个关键问题导致结果不符合预期,咱们一步步来梳理和修正:

一、代码里的核心问题分析

  1. 变量与循环范围错误

    • 你定义了number_of_points但循环里用了未定义的number_robots,这会直接引发报错;
    • 计算点对差异时,循环只覆盖了前2个点(range(2)),但你要处理3个点,应该枚举所有不重复的点对i < j),避免重复计算同一对点的距离。
  2. 欧氏距离平方计算逻辑混乱

    • ^运算符是完全错误的!在Python里这是按位异或,不是平方运算,平方应该用**2
    • 变量a_diff从未定义,应该对应你之前创建的difference列表;
    • 你没有累加所有点对的距离平方,反而用单个distance_sq变量反复覆盖,目标函数应该是所有点对的(x差平方 + y差平方)之和。
  3. 约束与变量范围不合理

    • 添加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

火山引擎 最新活动