首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >用OR工具CP求解分配优化问题的唯一性约束

用OR工具CP求解分配优化问题的唯一性约束
EN

Stack Overflow用户
提问于 2022-06-01 11:07:31
回答 1查看 163关注 0票数 1

我试图解决的问题与OR-tools文档中描述的问题非常相似:https://developers.google.com/optimization/assignment/assignment_example#cp_sat_solution。我有15名员工,我需要分配给5项任务。目标函数是最小化成本。但是,所选的工作人员需要准确地属于3个状态。我有一个问题,表达这一限制。代码如下

-用溶液编辑

代码语言:javascript
运行
复制
start_time = time.perf_counter()
costs = [500, 75, 80, 25, 95, 100, 10, 30, 400, 50, 80, 110, 150, 20, 60]
# states_label = ["AZ","CT","FL","CA","NY","CA","NY","CT","AZ","CA","CT","CT","AZ","FL","NY"]
states = [0,2,3,1,4,1,4,2,0,1,2,2,0,3,4]

num_workers = len(costs)
num_tasks = 5
num_states = 5

# Model
model = cp_model.CpModel()

# Variables
x = {}
for worker in range(num_workers):
    for task in range(num_tasks):
        x[worker, task] = model.NewBoolVar(f'x[{worker},{task}]')

# Create 
states_is_selected = []
for state in range(num_states):
    state_is_selected = model.NewBoolVar('')
    # workers_from_that_states are all x that corresponds to this state
    workers_from_that_state = []
    for worker in range(num_workers):
        for task in range(num_tasks):
            if (state == states[worker]):
                workers_from_that_state.append( x[worker,task])
    # print(f"state {state}")
    # print(workers_from_that_state)
    literals = [c for c in workers_from_that_state]
    model.AddBoolOr(literals).OnlyEnforceIf(state_is_selected)
    for literal in literals:
        model.AddImplication(literal, state_is_selected)
    
    states_is_selected.append(state_is_selected)


# Constraints

# Each worker is assigned to at most 1 task.
for worker in range(num_workers):
    model.AddAtMostOne(x[worker,task] for task in range(num_tasks))

# Each task is assigned to exactly one worker.
for task in range(num_tasks):
    model.AddExactlyOne(x[worker,task] for worker in range(num_workers))

# The workers belong to exactly 3 states
model.Add(sum(states_is_selected) == 3)


# Objective
objective_terms = []
for worker in range(num_workers):
    for task in range(num_tasks):
        objective_terms.append(costs[worker] * x[worker,task])

model.Minimize(sum(objective_terms))

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


print(f'Status = {solver.StatusName(status)}')
if status == cp_model.INFEASIBLE:
    print('SufficientAssumptionsForInfeasibility = 'f'{solver.SufficientAssumptionsForInfeasibility()}')

# Print solution.
if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
    
    print(f"Solution found")
    
    print(f'Total cost = {solver.ObjectiveValue()}')
    print()
    for worker in range(num_workers):
        for task in range(num_tasks):
            if solver.BooleanValue(x[worker,task]):
                print(f"Worker {worker}, Cost: {costs[worker]}, State: {states[worker]}")   

    for state in range(num_states):
        print(f"State {state}: ", solver.BooleanValue(states_is_selected[state]))

    # Number of States for assigned workers
    states_selected = [states[worker] for worker in range(num_workers) for task in range(num_tasks) if solver.BooleanValue(x[worker,task])]
    print(f"The workers selected are coming from {len(list(set(states_selected)))} states:", set(states_selected))


else:  
    print(f"No solution found")

    
end_time = time.perf_counter()
print("Program executed in {:,.2f} s".format(end_time - start_time))
EN

回答 1

Stack Overflow用户

发布于 2022-06-01 11:18:11

每个状态需要一个布尔变量。

然后实施

代码语言:javascript
运行
复制
state_is_selected <=> bool_or(workers_from_that_state)

这是一个简单的泛化:https://github.com/google/or-tools/blob/stable/ortools/sat/docs/boolean_logic.md#product-of-two-boolean-variables

然后是sum(states) == 3

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72460787

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档