我知道算法存在但是我在命名它并找到合适的解决方案时遇到了问题。
我的问题如下:
我有一组需要完成的J作业。
所有工作都需要不同的时间才能完成,但时间已知。
我有一套R资源。
每个追索权R可以包含1到100个实例中的任何数字。
作业可能需要使用任意数量的资源R。
作业可能需要使用资源R的多个实例,但从不超过资源R具有实例。 (如果资源只有2个实例,则作业永远不会超过2个实例)
作业完成后,会将其使用的所有资源的所有实例返回到池中以供其他作业使用。
作业一旦开始就无法被抢占。
只要资源允许,就可以同时执行的作业数量没有限制。
这不是有向图问题,作业J可以按任何顺序执行,只要它们可以声明其资源即可。
我的目标: 调度作业以最小化运行时间和/或最大化资源利用率的最佳方式。
答案 0 :(得分:2)
我不确定这个想法有多好,但您可以将其建模为整数线性程序,如下所示(未经测试)
定义一些常量,
Use[j,i] = amount of resource i used by job j
Time[j] = length of job j
Capacity[i] = amount of resource i available
定义一些变量,
x[j,t] = job j starts at time t
r[i,t] = amount of resource of type i used at time t
slot[t] = is time slot t used
约束是,
// every job must start exactly once
(1). for every j, sum[t](x[j,t]) = 1
// a resource can only be used up to its capacity
(2). r[i,t] <= Capacity[i]
// if a job is running, it uses resources
(3). r[i,t] = sum[j | s <= t && s + Time[j] >= t] (x[j,s] * Use[j,i])
// if a job is running, then the time slot is used
(4). slot[t] >= x[j,s] iff s <= t && s + Time[j] >= t
第三个约束意味着如果作业最近启动到足以使其仍在运行,则其资源使用会被添加到当前使用的资源中。第四个约束意味着如果作业最近启动到足以使其仍在运行,则使用此时间段。
目标函数是时隙的加权和,后续时隙的权重更高,因此它更喜欢填充早期时隙。理论上,权重必须呈指数级增长,以确保使用较晚的时间段总是比仅使用较早时间段的任何配置更差,但解算器不喜欢这样,在实践中,您可能可以使用较慢的增长权重。
你需要足够的插槽以便存在解决方案,但最好不要超过你最终需要的数量,所以我建议你从一个贪婪的解决方案开始,给你一个有希望的非平凡的上限时间插槽(显然还有所有任务的长度总和)。
有很多方法可以获得贪婪的解决方案,例如,只需在最早的时间段内逐个安排作业。通过某种程度的硬度来定购它们可能会更好。并把硬盘放在第一位,例如你可以根据他们使用资源的程度(例如,Use[j,i] / Capacity[i]
的总和,或者可能是最大值?谁知道,尝试一些事情)给他们一个分数然后按降序排列。
作为奖励,你可能并不总是必须解决完整的ILP问题(这是NP难的,所以有时它可能需要一段时间),如果你只解决线性松弛(允许变量采用小数值,不只是0或1)你得到一个下限,而近似的贪婪解决方案给出了上限。如果它们足够接近,您可以跳过昂贵的整数阶段并采取贪婪的解决方案。在某些情况下,如果线性松弛的舍入目标与贪婪解决方案的目标相同,这甚至可以证明贪婪解是最优的。
答案 1 :(得分:1)
这可能是Dykstra's Algorithm的工作。对于您的情况,如果您想最大限度地利用资源,那么搜索空间中的每个节点都是将作业添加到您将立即执行的作业列表的结果。然后,边缘将是您将作业添加到您将要执行的作业列表时留下的资源。
然后,目标是找到节点的路径,该节点的入口边缘是最小值。
另一种更直接的选择是将其视为knapsack problem。
要将此问题构建为背包问题的实例,请执行以下操作:
假设我有J
个职位,j_1, j_2, ..., j_n
和R
个资源,我想找到J
的子集,以便在安排该子集时{{1}最小化(我称之为R
)。
:
J'