分配问题:座席人数多于任务,但任务容量大

问题描述

我一直在使用一个预先存在的作业工具,该工具用于将本科生分配给项目。我现在很想尝试在python中构建一个赋值工具,这将使我能够添加和调​​整约束,因为由于COVID面临着空间使用方面的巨大压力。

任务的基础是让尽可能多的学生与他们喜欢的导师一起。我有85名学生,他们提供了1到5个优先级主管的排名,这使我可以调整成本变量。此外,还有40位主管,每位主管的能力水平各不相同;有些可以容纳2名学生,有些可以容纳3名,总容量约为100。

到目前为止,我一直在使用Google OR-Tools和python实现,并尝试使用CP-SAT和MIP进行“任务大小分配”策略。我可以使用CP-SAT为小型虚拟数据集生成解决方案,但是当我使用成本矩阵为85x40的去年数据时,我无法生成分配解决方案。相反,MIP求解器方法产生的分配为“ 0成本”,而没有实际分配。我也已经开始构建最小流量模型,但是到目前为止,我还无法使程序在我的输入数据上运行。

我的一般问题是“对于这样的分配问题,即代理人数多于任务,但任务接受能力大于1个代理的任务,什么是最佳的一般方法?”

很高兴提供有用的代码。 谢谢,戴夫

编辑 下面是我一直在尝试CP-SAT解决方案的代码。最初,我填充一个由学生数量和职员数量定义的大小的np数组,并使用值100填充它。这是我在成本矩阵中无法选择的元素所使用的。我接受了学生的选择(1至5),并进行平方以给出一些区别:

    from __future__ import print_function
    from ortools.sat.python import cp_model
    import time
    import pandas as pd
    import numpy as np

    capacity=pd.read_excel(r'C:\Users\Dave\Documents\assign_2019.xlsx',index_col=0,sheet_name='capacity')
    capacity=capacity.reset_index()
    choices=pd.read_excel(r'C:\Users\Dave\Documents\assign_2019.xlsx',sheet_name='choices')
    choices=choices.reset_index()

    array=np.empty((len(choices),len(capacity)))
    array.fill(100)
    cost = pd.DataFrame(data=array)
    cost.index=choices['student']
    cost.columns=capacity['staff']

    choices=choices.set_index(['student'])
    for i in choices.index:
        for j in choices.columns:
             s=choices.loc[i,j]
             cost.loc[i,s]=j**2

     cost=cost.to_numpy()
     cost=cost.astype(int)

     sizes = capacity['capacity']
     sizes=sizes.to_numpy()
     sizes=sizes.astype(int)

    def main():
      model = cp_model.CpModel()
      start = time.time()

       num_workers = len(cost)
       num_tasks = len(cost[1])
       # Variables
       x = []
         for i in range(num_workers):
         t = []
         for j in range(num_tasks):
                 t.append(model.NewIntvar(0,1,"x[%i,%i]" % (i,j)))
           x.append(t)
          x_array = [x[i][j] for i in range(num_workers) for j in 
       range(num_tasks)]

     # Constraints
        # Each staff is allocated no more than capacity.
        [model.Add(sum(x[i][j] for i in range(num_workers)) <= sizes[j])
        for j in range(num_tasks)]

         # Number of projects allocated to a student is 1.
        [model.Add(sum(x[i][j] for j in range(num_tasks)) == 1)
        for i in range(num_workers)]

        model.Minimize(sum([np.dot(x_row,cost_row) for (x_row,cost_row) in 
        zip(x,cost)]))
        solver = cp_model.cpsolver()
        status = solver.solve(model)

         if status == cp_model.OPTIMAL:
            print('Minimum cost = %i' % solver.ObjectiveValue())
            print()

    for i in range(num_workers):
          for j in range(num_tasks):
            if solver.Value(x[i][j]) >= 1:
              print('Worker ',i,' assigned to task ',j,'  Cost = ',cost[i][j])
           print()
           end = time.time()
           print("Time = ",round(end - start,4),"seconds")

      if __name__ == '__main__':
       main()

编辑2: 用于MIP求解器的代码(数据输入与上述CP-SAT尝试相同):

       def main():
         solver = pywraplp.solver('SolveAssignmentProblem',pywraplp.solver.CBC_MIXED_INTEGER_PROGRAMMING)

        start = time.time()

        num_workers = len(cost)
        num_tasks = len(cost[1])
         # Variables
        x = {}

      for i in range(num_workers):
           for j in range(num_tasks):
             x[i,j] = solver.Intvar(0,'x[%i,%i]' % (i,j))

         # Constraints
         # Staff can accept students up to capacity.

         for i in range(num_workers):
           solver.Add(solver.Sum([x[i,j] for j in range(num_tasks)]) <= 
       sizes[j])

          # Student is allocated 1 project.

          for j in range(num_tasks):
           solver.Add(solver.Sum([x[i,j] for i in range(num_workers)]) == 1)

          solver.Minimize(solver.Sum([cost[i][j] * x[i,j] for i in 
    range(num_workers)             
                                              for j in range(num_tasks)]))


          print('Minimum cost = ',solver.Objective().Value())
          print()
          for i in range(num_workers):
          for j in range(num_tasks):
            if x[i,j].solution_value() > 0:
              print('Worker',' assigned to task',cost[i] 
   [j])
        print()
         end = time.time()
         print("Time = ","seconds")
      if __name__ == '__main__':
        main()

尝试进行MIP的结果是:

       Minimum cost =  0.0


       Time =  0.553 seconds

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)