【问题标题】:Calculate hired days in a scheduling problem计算调度问题中的雇佣天数
【发布时间】:2019-07-18 13:00:19
【问题描述】:

在调度问题中,我还想尽量减少总雇佣天数。

如果员工在某天之前和之后工作,他/她就会在某一天被雇用。

这是一个小的工作示例:

import random
from ortools.sat.python import cp_model

model = cp_model.CpModel()
solver = cp_model.CpSolver()

employees = range(3)
days = range(10)

works_day = {(e, d): model.NewBoolVar(f'{e}_works_{d}')
             for e in employees for d in days}
hired_day = {(e, d): model.NewBoolVar(f'{e}_employed_{d}')
             for e in employees for d in days}

# random example
for boolean in works_day.values():
    model.Add(boolean == random.choice([0, 1]))

# give value to hired_day
add_hired_days()

# solve
print('Variables:', len(model.Proto().variables))
print('Constraints:', len(model.Proto().constraints))
status = solver.Solve(model)

for e in employees:
    print()
    print('Employee', e)
    for d in days:
        print('Works', solver.Value(works_day[e, d]),
              'Hired', solver.Value(hired_day[e, d]))

add_hired_days 在哪里:

def add_hired_days():
    for idx, d in enumerate(days):
        for e in employees:
            model.AddImplication(works_day[e, d], hired_day[e, d])
            previous = [works_day[e, d] for d in days[:idx + 1]]
            following = [works_day[e, d] for d in days[idx:]]

            # too many variables
            works_previous = model.NewBoolVar('')
            works_following = model.NewBoolVar('')

            model.AddBoolOr(previous).OnlyEnforceIf(works_previous)
            model.AddBoolAnd([d.Not() for d in previous
                              ]).OnlyEnforceIf(works_previous.Not())

            model.AddBoolOr(following).OnlyEnforceIf(works_following)
            model.AddBoolAnd([d.Not() for d in following
                              ]).OnlyEnforceIf(works_following.Not())

            model.AddBoolAnd([works_previous, works_following
                              ]).OnlyEnforceIf(hired_day[e, d])
            model.AddBoolOr([works_previous.Not(),
                             works_following.Not()
                             ]).OnlyEnforceIf(hired_day[e, d].Not())

有没有办法在不创建这么多变量和约束的情况下做到这一点?

【问题讨论】:

    标签: python scheduling constraint-programming or-tools


    【解决方案1】:

    如果一个员工一个月工作 n 天,他需要被雇用 n - 2 次。

    【讨论】:

    • 嗯,不确定我们是否使用相同的受雇定义,在我的情况下,如果员工在某一天之前和那天之后工作,那么他/她会在某一天被雇用,所以如果他工作 n 天,他被雇用 >= n 天。
    • sohired_day = last_worked_day - first_worked_day + 1 ?
    • 谢谢!关于如何获得第一天和最后一天的任何建议?不必效法我的榜样
    • 对于每一天 d,创建两个变量 v1[d] = d * working_var[d] 和 v2[d] = horizo​​n + working_var * (d - horizo​​n)。然后model.AddMinEquality(first_day_worked, v2), model.AddMaxEquality(last_day_worked, v1)
    【解决方案2】:

    按照Laurent的建议解决。

    import random
    from ortools.sat.python import cp_model
    
    if __name__ == '__main__':
        model = cp_model.CpModel()
        solver = cp_model.CpSolver()
    
        employees = range(3)
        days = range(10)
        horizon = len(days) - 1
    
        works_day = {(e, d): model.NewBoolVar(f'{e}_works_{d}')
                     for e in employees for d in days}
        hired_days = [
            model.NewIntVar(0, len(days), f'{e}_hired') for e in employees
        ]
        first_day = [
            model.NewIntVar(0, horizon, f'{e}_first_day') for e in employees
        ]
        last_day = [
            model.NewIntVar(0, horizon, f'{e}_last_day') for e in employees
        ]
    
        # random example
        for boolean in works_day.values():
            model.Add(boolean == random.choice([0, 1]))
    
        for e in employees:
            v1 = [model.NewIntVar(0, horizon, '') for _ in days]
            v2 = [model.NewIntVar(0, horizon, '') for _ in days]
            for d in days:
                model.Add(v1[d] == d * works_day[e, d])
                model.Add(v2[d] == horizon + works_day[e, d] * (d - horizon))
            model.AddMinEquality(first_day[e], v2)
            model.AddMaxEquality(last_day[e], v1)
            model.Add(hired_days[e] == last_day[e] - first_day[e] + 1)
    
        # solve
        status = solver.Solve(model)
    
        for e in employees:
            print()
            print('Employee', e)
            for d in days:
                print('Works', solver.Value(works_day[e, d]))
            print('First day:', solver.Value(first_day[e]), 'Last day:',
                  solver.Value(last_day[e]), 'Hired:', solver.Value(hired_days[e]))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-13
      • 2021-07-27
      • 2019-03-02
      • 2017-02-01
      相关资源
      最近更新 更多