使用 ortools select 列表中的两个最小整数值

Using ortools to select the two smallest integer values in a list

我知道 ortools 在这里有点矫枉过正,但这是为了我自己边做边学的目的。

问题是:如何使用 ortools 找到列表中的两个最小整数值?

这是我得到的代码,基于我得到的另一个例子,它只是找到单个最小值。

from __future__ import print_function
from ortools.sat.python import cp_model

# 2. A simple problem

# Select the two smallest numbers from a list of integers

# Define data

cost_data = [
    5, 4, 3, 4, 5, 6, 7, 1, 2, 3
]
num_hours = len(cost_data)
hours = range(num_hours)

# Create model

model = cp_model.CpModel()

# Create variables

cost_vars = {}
pick_vars = {}
for i in hours:
    for j in hours:
        cost_vars[(i, j)] = model.NewIntVar(0, 100, 'c_%i_%i' % (i, j))
        pick_vars[(i, j)] = model.NewBoolVar('p_%i_%i' % (i, j))

# Create constraints

# An hour can only be picked once

for i in hours:
    model.Add(sum(pick_vars[(i, j)] for j in hours) == 1)

# Only set cost if applicable

for i in hours:
    for j in hours:
        model.Add(cost_vars[(i, j)] == cost_data[i] + cost_data[j]).OnlyEnforceIf(pick_vars[(i, j)])
        model.Add(cost_vars[(i, j)] == 0).OnlyEnforceIf(pick_vars[(i, j)].Not())

# Set objective function
for i in hours:
    model.Minimize(sum([cost_vars[(i, j)] for j in hours]))

# Solve problem
solver = cp_model.CpSolver()
status = solver.Solve(model)

if status == cp_model.INFEASIBLE:
    print("INFEASIBLE")
elif status == cp_model.FEASIBLE:
    print("FEASIBLE")
elif status == cp_model.OPTIMAL:
    print("OPTIMAL")

print("ObjectiveValue()")
print(solver.ObjectiveValue())

# print(solver.Value(cost_vars[(1, 2)]))

它returns值4,当实际值应该是3...

存在多个问题:

你应该只调用一次 Minimize 或 Maximize,只有最后一个才会生效,所以我猜你想要 model.Minimize(sum(cost_vars.values()))

这个我也不懂:

for i in hours:
    model.Add(sum(pick_vars[(i, j)] for j in hours) == 1)

也许你的意思是:

model.Add(sum(pick_vars.values()) == 1)

而且在这里你应该检查是否 i != j:

for i in hours:
    for j in hours:

编辑:如果i != j那么一开始就不要创造可能性

for i in hours:
    for j in hours:
        if i != j:
            cost_vars[(i, j)] = model.NewIntVar(0, 100, 'c_%i_%i' % (i, j))
            pick_vars[(i, j)] = model.NewBoolVar('p_%i_%i' % (i, j))