请帮助您优化this工作的MiniZinc代码:

任务:有一个6x时隙的会议。有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     |          |
+---+----------+----------+----------+

最佳答案

我是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”。)

09-25 22:14