我刚刚开始研究涉及一些调度优化的项目,我担心自己处于数学水域。我想知道你是否能想出任何聪明的方法来做到以下几点。
以下是基础知识:
约束:
最终,某些公式将用于计算每个有效配置的加权分数,以确定董事会的“最佳”状态。为了便于解释,我们只会说它类似于2a + 5b,其中a和b是访调员与申请人共有的不同质量,但现在这并不重要。
我试图想出一些方法来生成所有可能的有效配置,并最终计算每个有效配置的得分,最后选择得分最高的配置。我找到一个聪明的方法遇到了一些问题。
最初,我并没有感到聪明,并且想到了暴力强迫它,但由于各种各样的可能性,这基本上是不可能的。
你能想到更复杂的方法来修剪一些错误的配置或巧妙的方法来生成有效的加权分数检查板吗?
答案 0 :(得分:1)
这是MiniZinc中一个非常简单的约束编程模型 - 给定适当的求解器 - 为问题(我的解释)生成所有可能的有效解决方案。但是,正如@TimChippingtonDerrick指出的那样,对于更复杂的问题实例,解决方案太多了。
那就是说,如果目标(obj =“2a + 5b”)可以在模型中以某种方式陈述(例如使用访调员/申请人的一些额外数据等),那么只需将其改为优化问题,即最小化或最大化该目标。
因此,这是一个简单问题实例的MiniZinc模型(x = 10,y = 5,z = 10,m = 3)。注意:在面试表中,值0(零)表示当时没有面试官面试。
include "globals.mzn";
int: x = 10; % number of time slots
int: y = 5; % number of faculty interviewers
int: z = 10; % number of applicants interviewing
int: m = 3; % number of times each applicants will be interviewed
% decision variables
% The interview table:
% 1..y: rows (interviewers)
% 1..x: columns (time slots)
array[1..y, 1..x] of var 0..z: s;
% solve satisfy;
solve :: int_search([s[i,j] | i in 1..y, j in 1..x], first_fail, indomain_random, complete) satisfy;
constraint
% A z digit can only appear once in each row/column like Sudoku (because an applicant
% can't interview with the same interviewer twice and he/she can't interview twice at once).
forall(a in 1..z) (
% rows
forall(i in 1..y) (
%sum([bool2int(s[i,j] = a) | j in 1..x]) <= 1
alldifferent_except_0([bool2int(s[i,j] = a) | j in 1..x])
)
/\
% columns
forall(j in 1..x) (
% sum([bool2int(s[i,j] = a) | i in 1..y]) <= 1
alldifferent_except_0([bool2int(s[i,j] = a) | i in 1..y])
)
)
% There has to be exactly 3 of each z number in the entire table
% (because all applicants have to interview exactly 3 times).
/\
forall(a in 1..z) (
count([s[i,j] | i in 1..y, j in 1..x], a, m)
)
;
% constraint
% % symmetry breaking: assign applicant a to interviewer a in time a (if possible)
% forall(a in 1..z where a <= y) (
% s[a,a] = a
% )
% ;
output [
"x (number of time slots (rows): " ++ show(x) ++ "\n" ++
"y (number of interviews (columns): " ++ show(y) ++ "\n" ++
"z (number of applicants): " ++ show(z) ++ "\n"
]
++
[
if j = 1 then "\n" else " " endif ++
show_int(2,s[i,j])
| i in 1..y, j in 1..x
];
对于这个问题(x = 10,y = 5,z = 10),有大量的解决方案。以下是其中两个:
x (number of time slots (rows): 10
y (number of interviews (columns): 5
z (number of applicants): 10
5 2 10 8 0 6 7 4 3 9
3 1 5 7 0 2 9 6 8 4
8 0 0 5 6 1 10 3 0 7
2 10 1 0 0 9 0 0 0 0
0 0 0 0 0 4 0 0 0 0
----------
x (number of time slots (rows): 10
y (number of interviews (columns): 5
z (number of applicants): 10
5 2 10 8 0 6 7 4 3 9
3 1 5 7 0 2 9 6 8 4
8 0 0 5 6 1 10 3 0 7
2 10 0 1 0 9 0 0 0 0
0 0 0 0 0 4 0 0 0 0
(这个MiniZinc模型也在这里:http://www.hakank.org/minizinc/interview_scheduling.mzn)
对一个更简单问题(x = 6,y = 3,z = 3,m = 3)的数字注释,以显示问题的多样性:当不使用对称性破坏时,有317760种不同的解决方案(评论为在代码中)。随着对称性打破它的解决方案要少得多:1300。以下是其中一个解决方案:
1 0 0 3 2 0
3 2 1 0 0 0
0 1 3 2 0 0
答案 1 :(得分:0)
在上面的回复中没有说明,可能是因为它对我们中的一些人来说很明显,但只是试图列举所有合法组合只会在这类问题的非常小的测试案例中起作用。如果你尝试一个天真的实现,你将很快在计算时间内碰壁。
正如其他人所建议的那样,如果您想针对实际问题进行此操作,则需要考虑使用一些优化工具。任何一个自由解算器,如COIN-OR,glpk或lpsolve;或者其中一种商业工具 - 它们可能会变得昂贵,但如果你有足够大的问题,那么它们很容易付出代价。