请帮助优化this正在使用的MiniZinc代码:
任务:会议有6个时段。参加会议的有3位发言者,每位发言者都可以在某些位置使用。每个发言者将呈现预定数量的时段。
目标:制作最早完成发言人的时间表。
示例:发言人A,B& C.谈话持续时间= [1,2,1]
演讲者可用性:
+---+------+------+------+
| | Sp.A | Sp.B | Sp.C |
+---+------+------+------+
| 1 | | Busy | |
| 2 | Busy | Busy | Busy |
| 3 | Busy | Busy | |
| 4 | | | |
| 5 | | | Busy |
| 6 | Busy | Busy | |
+---+------+------+------+
链接到工作的MiniZinc代码:http://pastebin.com/raw.php?i=jUTaEDv0
我希望优化的内容:
% ensure allocated slots don't overlap and the allocated slot is free for the speaker
constraint
forall(i in 1..num_speakers) (
ending_slot[i] = starting_slot[i] + app_durations[i] - 1
) /\
forall(i,j in 1..num_speakers where i < j) (
no_overlap(starting_slot[i], app_durations[i], starting_slot[j], app_durations[j])
) /\
forall(i in 1..num_speakers) (
forall(j in 1..app_durations[i]) (
starting_slot[i]+j-1 in speaker_availability[i]
)
)
;
预期解决方案:
+---+----------+----------+----------+
| | Sp.A | Sp.B | Sp.C |
+---+----------+----------+----------+
| 1 | SELECTED | Busy | |
| 2 | Busy | Busy | Busy |
| 3 | Busy | Busy | SELECTED |
| 4 | | SELECTED | |
| 5 | | SELECTED | Busy |
| 6 | Busy | Busy | |
+---+----------+----------+----------+
答案 0 :(得分:4)
我是hakank(原始模型的作者)。如果我理解正确,你现在的问题是如何提供表格以获得最佳解决方案,而不是真正找到解决方案本身(我测试的所有FlatZinc求解器都能立即解决)。
创建表格的一种方法是有一个帮助矩阵(“m”),如果选择了一个扬声器(1),忙(-1)或不可用(0),它包含信息:
array[1..num_slots, 1..num_speakers] of var -1..1: m;
然后必须在矩阵和其他决策变量(“starting_slot”和“ending_slot”)中连接信息:
% connect to matrix m
constraint
forall(t in 1..num_slots) (
forall(s in 1..num_speakers) (
(not(t in speaker_availability[s]) <-> m[t,s] = -1)
/\
((t >= starting_slot[s] /\ t <= ending_slot[s]) <-> m[t,s] = 1)
)
)
然后矩阵“m”可以这样打印:
% ...
++
[
if s = 1 then "\n" else " " endif ++
if fix(m[t,s]) = -1 then
"Busy "
elseif fix(m[t,s]) = 1 then
"SELECTED"
else
" "
endif
| t in 1..num_slots, s in 1..num_speakers
] ;
与往常一样,有不止一种方法可以做到这一点,但我对此已经解决了,因为它非常直接。
这是完整的模型: http://www.hakank.org/minizinc/scheduling_speakers_optimize.mzn
更新:添加模型的输出:
Starting: [1, 4, 3]
Durations: [1, 2, 1]
Ends: [1, 5, 3]
z: 5
SELECTED Busy
Busy Busy Busy
Busy Busy SELECTED
SELECTED
SELECTED Busy
Busy Busy
----------
==========
更新2: 另一种方法是使用累积/ 4而不是no_overlap / 4,这应该更有效,即
constraint
forall(i in 1..num_speakers) (
ending_slot[i] = starting_slot[i] + app_durations[i] - 1
)
% /\ % use cumulative instead (see below)
% forall(i,j in 1..num_speakers where i < j) (
% no_overlap(starting_slot[i], app_durations[i], starting_slot[j], app_durations[j])
% )
/\
forall(i in 1..num_speakers) (
forall(j in 1..app_durations[i]) (
starting_slot[i]+j-1 in speaker_availability[i]
)
)
/\ cumulative(starting_slot, app_durations, [1 | i in 1..num_speakers], 1)
;
这是更改后的版本(给出相同的结果) http://www.hakank.org/minizinc/scheduling_speakers_optimize2.mzn (我也跳过了表示矩阵“m”并在输出部分做了所有演示。)
对于这个简单的问题实例,没有明显的区别,但对于较大的实例,这应该更快。 (对于较大的实例,可能需要测试不同的搜索启发式而不是“求解最小化z”。)
答案 1 :(得分:2)
正如我对您之前的问题Constraint Programming: Scheduling speakers in shortest time所评论的那样,累积约束适用于此。我没有Minizinc代码方便,但ECLiPSe(http://eclipseclp.org)中有模型:
:- lib(ic).
:- lib(ic_edge_finder).
:- lib(branch_and_bound).
solve(JobStarts, Cost) :-
AllUnavStarts = [[2,6],[1,6],[2,5]],
AllUnavDurs = [[2,1],[3,1],[1,1]],
AllUnavRess = [[1,1],[1,1],[1,1]],
JobDurs = [1,2,1],
Ressources = [1,1,1],
length(JobStarts, 3),
JobStarts :: 1..9,
% the jobs must not overlap with each other
cumulative(JobStarts, JobDurs, Ressources, 1),
% for each speaker, no overlap of job and unavailable periods
(
foreach(JobStart,JobStarts),
foreach(JobDur,JobDurs),
foreach(UnavStarts,AllUnavStarts),
foreach(UnavDurs,AllUnavDurs),
foreach(UnavRess,AllUnavRess)
do
cumulative([JobStart|UnavStarts], [JobDur|UnavDurs], [1|UnavRess], 1)
),
% Cost is the maximum end date
( foreach(S,JobStarts), foreach(D,JobDurs), foreach(S+D,JobEnds) do true ),
Cost #= max(JobEnds),
minimize(search(JobStarts,0,smallest,indomain,complete,[]), Cost).