我想做一个没有重叠的时间表,只有1位老师可以在1个时段预订。我想创建像教师一样的2darray,行和时间段是coloumns。
答案 0 :(得分:2)
用于这些约束的一般约束("某些东西应该是不同的")是两个全局约束all_different或alldifferent_except_0。
注意:我更改为3位教师,3位时段和5位演示文稿,以便更广泛地使用alldifferent_except_0,因为可以在没有教师/时间段的情况下进行演示。
另外,我不确定我会像你一样使用特定的表示,因为它的表示取决于模型中的进一步约束(如果有的话)。
以下是一些可能有用的方法。
1)简单的模型只有一个"时间表"基质
如果您只想分配没有进一步约束的T教师,TS时隙和P演示文稿,那么单个约束" all_different_except_0"在时间表矩阵上就足够了(连同下面解释的总和)。 "时间表的维度"是我们分配演示文稿的T x TS(教师x时间段),如果没有该教师和时间段的演示文稿,则为0。
include "globals.mzn";
set of int: Timeslots = 1..3;
set of int: Teachers = 1..3;
set of int: Presentations = 1..5;
solve satisfy;
% Decision variables
array[Teachers, Timeslots] of var {0} union Presentations: timetable;
constraint
alldifferent_except_0(array1d(timetable))
% ensure that there are 5 assigned presentations
/\ sum([timetable[t,ts]>0 | t in Teachers, ts in Presentations]) = card(Presentations)
;
% output [....];
这种模式的缺点是不容易说出可能需要的进一步约束,而且我们必须计算"时间表中的非0分配的数量"矩阵,以确保分配了5个演示文稿。
因此我们将扩展更多的决策变量。
2)添加决策变量
此模型将原始演示文稿与"时间表"矩阵及其约束如上所示。这意味着我们可以将约束保留在"时间表"为了确保单一性,我们也可以对其他决策变量进行约束。这是一个带有两个原始数组" presentation_teacher"和" presentation_time"和他们的约束。
include "globals.mzn";
set of int: Timeslots = 1..3;
set of int: Teachers = 1..3;
set of int: Presentations = 1..5;
% Decision variables
% Which teacher has this presentation
array[Presentations] of var Teachers: presentation_teacher;
% Which timeslot for this presentation
array[Presentations] of var Timeslots: presentation_time;
% Which combination of teacher and timeslot for a presentation, if any
array[Teachers, Timeslots] of var {0} union Presentations: timetable;
solve satisfy;
constraint
alldifferent_except_0(array1d(timetable))
% This constraint is not needed now
% /\ sum([timetable[t,ts]>0 | t in Teachers, ts in Presentations]) = card(Presentations)
/\ % connect timetable and presentation_teacher and presentation_time
forall(p in Presentations) (
timetable[presentation_teacher[p],presentation_time[p]] = p
)
;
约束" forall(p in Presentations)(...)"连接两个表示:"时间表"表示和两个添加的数组。
3)替代版本
为教师确保不同时间段和演示文稿的替代版本是在" presentation_teacher"," presentation_time"上添加约束。这并不需要时间表矩阵,因此在此处略过了。 (可以用时间表方法添加这些约束可能会更快。)
include "globals.mzn";
set of int: Timeslots = 1..3;
set of int: Teachers = 1..3;
set of int: Presentations = 1..5;
% Decision variables
% Which teacher has this presentation
array[Presentations] of var Teachers: presentation_teacher;
% Which timeslot for this presentation
array[Presentations] of var Timeslots: presentation_time;
solve satisfy;
constraint
% variant A
forall(t in Teachers) (
% the time for this teacher is distinct (or 0)
alldifferent_except_0([presentation_time[p] * (presentation_teacher[p]=t) | p in Presentations])
)
/\
% variant B
forall(t in Teachers) (
% combination of (time + teacher) for this teacher is unique
alldifferent([presentation_time[p]+(presentation_teacher[p]*card(Presentations)) | p in Presentations])
)
;
这个模型有两个变体,第一个(" A")使用alldifferent_except_0来确保每个教师的演示文稿是不同的。
对于每位教师,它会遍历所有演示文稿(" p")并选择分配给"""老师,并确保他们是独特的。
第二种变体(" B")有点像黑客,虽然有时非常有用:它建立了一个为教师分配的整数列表(时间+ teacher_id *演示数量)并确保这些是截然不同的。
由于该模型没有明确的时间表,因此必须在输出中提取时间表。这是一种方式:
output [
"Teacher " ++ show(t) ++ " has these presentations" ++ show([p | p in Presentations where fix(presentation_teacher[p]) = t]) ++ "\n"
| t in Teachers
]
;
如上所述,模型的表示(要选择的决策变量)很大程度上取决于人们想要做的事情。