【发布时间】:2021-08-06 09:51:05
【问题描述】:
我有一个扇区列表,每个扇区都有一定的容量。例如:
Sectors = {
"1A": 80,
"1B": 20,
"2A": 10,
"3A": 50,
"3B": 20,
"3C": 110
}
我还有一个团队列表,每个团队都有一定数量的成员,例如:
Teams = {
"TeamA":20,
"TeamB":15,
"TeamC":100,
"TeamD":20,
"TeamF":85,
"TeamG":35,
"TeamH":25,
"TeamI":7,
}
请注意,团队多于部门,并且每个团队中的团队成员总数高于部门容量总数,因此会有没有部门的团队。
现在我需要将每个团队与部门匹配,这样:
- 已分配部门的团队中的团队成员总数最大化
对于约束有:
- 团队大小不能超过分配的扇区大小(例如:TeamC 只能放入整个扇区 3C,除非按照约束 2 中的描述将其分成两个)
现在这更难了:
- 一个 Team 可以分配到多个扇区,但扇区必须以相同的编号开头(例如:TeamC 可以分配给 1A 和 1B,但不能分配给 1A 和 3B)
- 一个部门只能分配一个团队。
- 团队需要完全适应或完全排除在外。
如果我的想法正确,第二个约束会使这个问题类似于多个背包问题,但我不确定一个团队是否是一个背包,而这些部门是我们装进麻袋的物品。因为在这种情况下,物品尺寸需要等于或大于麻袋容量。
由于这个限制,我很迷茫我应该使用什么样的算法来解决这个问题,或者这个问题是否真的可以以这种形式解决。 有谁知道解决这个问题的尽可能简单的python算法吗?
编辑:添加代码:
目前我正在使用 ORTools 库来解决这个问题: 变量:
x = {}
for i in data['sector_number']:
for j in data['teams']:
x[(i, j)] = solver.IntVar(0, 1, 'x_%i_%i' % (i, j))
# y[j] = 1 if team j has allocated sector.
y = {}
for j in data['teams']:
y[j] = solver.IntVar(0, 1, 'y[%i]' % j)
这是我的限制:
# Each sector can be allocated to at most one team.
for i in data['sector_number']:
solver.Add(sum(x[i, j] for j in data['teams']) <= 1)
# The sector seats amount allocated to each team needs to be minimum this team capacity
for j in data['teams']:
solver.Add(sum(x[(i, j)] * data['sector_capacity'][i] for i in data['sector_number']) >= y[j] * data['team_members'][j])
最后是客观的:
# Objective
objective = solver.Objective()
solver.Maximize(solver.Sum([y[j] for j in data['teams']]))
因此,实际上唯一缺少的约束条件是,如果将多个扇区分配给一个团队,则只能在开始时分配相同编号的扇区。
这是为此的数据输入:
{'sector_capacity': [80, 20, 10, 50, 20, 110],
'sector_number': [0, 1, 2, 3, 4, 5],
'sector_names': ['1A', '1B', '2A', '3A', '3B', '3C']
'num_sectors': 6,
'teams': [0, 1, 2, 3, 4, 5, 6, 7],
'team_names': ['TeamA',
'TeamB',
'TeamC',
'TeamD',
'TeamE',
'TeamF',
'TeamG',
'TeamH',
'TeamI'],
'team_members': [20, 15, 100, 20, 85, 35, 25, 7]}
【问题讨论】:
-
你总是可以使用蛮力。根据您实际问题的大小,这可能足够快。
-
输入 JSON 中的扇区 1A 和 1B 在哪里?
-
@Rizquuula 抱歉,已更新。
标签: python mathematical-optimization knapsack-problem or-tools bin-packing