问题
I know ortools is overkill here, but this is for my own learning-by-doing purpose.
The problem is: How to find the two smallest integer values in a list using ortools?
Here's the code I've got, based on another example I got that simply finds the single smallest value.
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)]))
It returns the value 4, when the actual value should be 3...
回答1:
There are multiple problems:
You should only call Minimize or Maximize once, only the last one will take effect, so I guess you want model.Minimize(sum(cost_vars.values()))
I also don't understand this:
for i in hours:
model.Add(sum(pick_vars[(i, j)] for j in hours) == 1)
Maybe you meant this instead:
model.Add(sum(pick_vars.values()) == 1)
And also here you should check whether i != j
:
for i in hours:
for j in hours:
Edit: if i != j
then don't create the possibility in the first place
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))
来源:https://stackoverflow.com/questions/57709665/using-ortools-to-select-the-two-smallest-integer-values-in-a-list