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

我的梦境 提交于 2019-12-11 06:08:22

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!