【问题标题】:How do you find the optimal assignment of pupils in classes?您如何找到班级中学生的最佳分配?
【发布时间】:2013-06-05 10:31:41
【问题描述】:

需要将 A 级的 23 名学生、B 级的 24 名学生和 C 级的 30 名学生分配到三个班级。 这些类需要几乎完全相同的大小。 不同的级别可以混合到一个类中,但是如果可以避免它会更好。在任何情况下,一个班级的一个级别应该有 0 个学生,或者超过 6 个。

你能帮我解决这个组合优化问题吗?下面是一个示例输入和输出。如果您能告诉我如何解决一般问题,则可以加分!

输入:

pupils = { "A" : 23, "B" : 24, "C": 30 }

示例输出(不是很好!)

Class #1 : {'A': 9,  'B': 6, 'C': 10},
Class #2 : {'A': 10, 'B': 9, 'C': 7},
Class #3 : {'A': 11, 'B': 9, 'C': 6}

编辑Here 是我非常骇人听闻的、完全无证的、半暴力破解的代码。这很丑陋,但它有效!我很想学习如何编写更优雅的解决方案。

【问题讨论】:

  • 您说示例输出“不是很好”。它出什么问题了?为什么其他 25-26-26 拆分会更好?
  • @jwpat7 :正如描述中所解释的,这不是很好,因为三个班级都有三个级别,这对老师来说比较难,最好避免。不过,类应该具有相同大小的约束比这个要强。
  • 你现在是怎么解决的?如,您是否使用优化求解器?如果是这样,您的限制和目标是什么?
  • @raoulcousins :不知道更好,我已经开始编写一个半暴力算法(我试图尽快消除不好的选项)。这可能会奏效,但我很想知道是否有更好或更优雅的选择。
  • 好的,我会写一个快速优化模型来概括它。你使用什么编程语言?你是如何选择边界 = 6 的?如果您在 N 中的每个级别 i 中都有 N 个级别和 p_i 个学生,那么 = 6 的界限将推广到什么?

标签: algorithm dynamic-programming combinatorics mathematical-optimization linear-programming


【解决方案1】:

这里的基本困难是你有一个多目标优化问题。我认为您对三件事感兴趣,可以考虑目标或“软约束”:

  1. 获得相似的班级规模
  2. 尽量减少每个班级的关卡数量
  3. 如果班级中有学生,则班级中的某个级别有足够的学生。

请注意,我已经在 AMPL 中为此编写了一个优化模型。由于您使用的是 Python,因此您可以使用类似的 Python 优化建模语言,例如 PuLP 和 pyomo。该模型应该不会太难翻译。

这是一个整数规划模型和一个数据文件,它强调目标数字 1,同时保持问题(整数)线性。有了这个目标,优化问题会找到您在示例中给出的相同解决方案。希望您能以此为基础,添加其他约束和/或客观术语,并获得更好的解决方案。

目标是最小化最大班级规模。感兴趣的变量是 y[i,j]。 y[i,j] for i in LEVEL, j in CLASS 是从级别 i 分配到班级 j 的学生人数。它假定您输入了每个班级中每个级别的最少学生人数(如果有分配到该级别)。

目标函数可能不是您想要的,但它是一种尝试均衡线性班级规模的方法。我也不保证这是解决问题的最有效方法。可能有更好的自定义算法来解决这个问题,但我所要做的就是表达约束和目标,而不是编写算法。它可能已经足够你使用了。

使用 neos-server.org 上的求解器 Gurobi(您可以使用 lpsolve 或其他开源优化求解器),我得到了解决方案

y :=
1 1   14
1 2    9
1 3    0
2 1    6
2 2    0
2 3   18
3 1    6
3 2   16
3 3    8
;

型号:

set LEVEL ordered;
set CLASS;

param maxClassSize {CLASS};
param minLevelNumberInClass {LEVEL, CLASS};
param numInLevel {LEVEL};

var z >= 0;
var y{LEVEL, CLASS} integer, >= 0;
var x{LEVEL, CLASS} binary;

#minimize maximum class size
minimize obj: 
  z;

subject to allStudentsAssigned {i in LEVEL}:
  sum {j in CLASS} y[i,j] = numInLevel[i];

#z is the largest of all classes sizes
subject to minMaxZ {j in CLASS}:
  z >= sum {i in LEVEL} y[i,j];

subject to maxClassSizeCon {j in CLASS}:
  sum {i in LEVEL} y[i,j] <= maxClassSize[j];

#xij = 1 if any students from level i are in class j
subject to defineX {i in LEVEL, j in CLASS}:
  y[i,j] <= min(numInLevel[i], maxClassSize[j]) * x[i,j];

#if any students from level i are assigned to class j, then there is a minimum
#if x[i,j] = 1,  y[i,j] >= minLevelNumberInClass[i,j]
subject to minLevel {i in LEVEL, j in CLASS}:
  minLevelNumberInClass[i,j] * x[i,j] <= y[i,j];

您的示例的数据文件:

set LEVEL := 1 2 3;
set CLASS := 1 2 3;

param minLevelNumberInClass:  
  1 2 3 :=
1 6 6 6
2 6 6 6
3 6 6 6
;

param maxClassSize :=
1 77
2 77
3 77
;

param numInLevel :=
1 23
2 24
3 30
;

【讨论】:

  • 谢谢,这是对线性规划世界的精彩介绍。非常感谢您花时间写这篇文章。
  • 没问题。如果那是一个介绍,我真的把你扔进了深渊。如果您对编写好的优化模型感兴趣,H. Paul Williams 的 Model Building in Mathematical Programming 是一本很棒的应用书籍。
  • 快速跟进问题:是否有可能得到多个最佳答案?这个问题有很多最佳答案,看到它们很有趣。
  • 是的,但这值得单独发布。这有一些细节:orinanobworld.blogspot.com/2012/05/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
  • 2021-01-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多