【问题标题】:Minizinc: output for five days,there is a better flexible way?Minizinc:输出五天,有更好灵活的方式吗?
【发布时间】:2014-11-26 16:13:47
【问题描述】:

我必须扩展我的项目的输出和解决方案(安排考试):

-将结构延长到五天(我一直都是一天工作): 我考虑过将 slottimes 的天数 (5*10) 计算出来,然后调整输出!有没有更好的办法?

现在是整个代码:

include "globals.mzn";include "alldifferent.mzn";

%------------------------------Scalar_data----------------------
int: Students;          % number of students
int: Exams;             % number of exams
int: Rooms;             % number of rooms
int: Slotstime;         % number of slots
int: Days;              % a period i.e. five days
int: Exam_max_duration; % the maximum length of any exam (in slots)

%------------------------------Vectors--------------------------
array[1..Rooms] of int  : Rooms_capacity;
array[1..Exams] of int  : Exams_duration; % the duration of written test
array[1..Slotstime, 1..Rooms] of 0..1: Unavailability;
array[1..Students,1..Exams]   of 0..1: Enrollments;

Enrollments 会跟踪每个学生的注册情况; 由此我得到了参加考试的学生人数, 为了根据容量选择合适的房间

%---------------------------Decision_variables------------------
array[1..Slotstime,1..Rooms] of var 0..Exams: Timetable_exams;
array[1..Exams] of var 1..Rooms: ExamsRoom;
array[1..Exams] of var 1..Slotstime: ExamsStart;

%---------------------------Constraints--------------------------

% Calculate the number of subscribers and assign classroom 
% according to time and capacity 

constraint forall (e in 1..Exams,r in 1..Rooms,s in 1..Slotstime)               
(if Rooms_capacity[r] <= sum([bool2int(Enrollments[st,e]>0)| st in 1..Students])
  then Timetable_exams[s,r] != e  
  else true
  endif
);

% Unavailability OK
constraint forall(c in 1..Slotstime, p in 1..Rooms)
(if Unavailability[c,p] == 1
  then Timetable_exams[c,p] = 0
  else true
  endif
);

% Assignment exams according with rooms and slotstimes   (Thanks Hakan)     
constraint forall(e in 1..Exams)                 % for each exam
(exists(r in 1..Rooms)                           % find a room
  ( ExamsRoom[e] = r         /\                  % assign the room to the exam
    forall(t in 0..Exams_duration[e]-1)               
% assign the exam to the slotstimes and room in the timetable
    (Timetable_exams[t+ExamsStart[e],r] = e)
  )
)
/\ % ensure that we have the correct number of exam slots

sum(Exams_duration) = sum([bool2int(Timetable_exams[t,r]>0) | t in 1..Slotstime, 
r in 1..Rooms]);

%---------------------------Solver--------------------------

solve satisfy;

%   solve::int_search([Timetable_exams[s, a] | s in 1..Slotstime, a in    
%   1..Rooms],first_fail,indomain_min,complete) satisfy;

现在的输出,极其沉重且充满了字符串。

%---------------------------Output--------------------------

output ["\n" ++ "MiniZinc paper: Exams schedule " ++ "\n" ]
++["\nDay I \n"]++      
[
if r=1 then "\n" else " " endif ++
show(Timetable_exams[t,r])
| t in 1..Slotstime div Days, r in 1..Rooms
]
++["\n\nDay II \n"]++ 
[
if r=1 then "\n" else " " endif ++
show(Timetable_exams[t,r])
| t in 11..((Slotstime div Days)*2), r in 1..Rooms
]
++["\n\nDay III \n"]++ 
[
if r=1 then "\n" else " " endif ++
show(Timetable_exams[t,r])
| t in 21..((Slotstime div Days)*3), r in 1..Rooms
]
++["\n\nDay IV \n"]++ 
[
if r=1 then "\n" else " " endif ++
show(Timetable_exams[t,r])
| t in 31..((Slotstime div Days)*4), r in 1..Rooms
]
++["\n\nDay V \n"]++ 
[
if r=1 then "\n" else " " endif ++
show(Timetable_exams[t,r])
| t in 41..Slotstime, r in 1..Rooms
]
++[ "\n"]++
[
"\nExams_Room:   ", show(ExamsRoom), "\n",
"Exams_Start:  ", show(ExamsStart), "\n",
]
++["Participants: "]++
[
if e=Exams then " " else " " endif ++
show (sum([bool2int(Enrollments[st,e]>0)| st in 1..Students]))
|e in 1..Exams
];

我完成了数据:

%Data
Slotstime=10*Days;
Students=50;
Days=5;

% Exams
Exams = 5;
Exam_max_duration=4;
Exams_duration = [4,1,2,3,2]; 

% Rooms
Rooms = 4;
Rooms_capacity   = [20,30,40,50];

Unavailability = [|0,0,0,0           % Rooms rows % Slotstime columns
|0,0,0,0
|0,0,0,0
|0,0,0,0
|1,1,1,1
|1,1,1,1
|0,0,0,0
|0,0,0,0
|0,0,0,0
|0,0,0,0
                                      % End first day
|0,0,0,0
|0,0,0,0
|0,0,0,0
|0,0,0,0
|1,1,1,1
|1,1,1,1
|0,0,0,0
|0,0,0,0
|0,0,0,0
|0,0,0,0
                                      % End secon day
|0,0,0,0
|0,0,0,0
|0,0,0,0
|0,0,0,0
|1,1,1,1
|1,1,1,1
|0,0,0,0
|0,0,0,0
|0,0,0,0
|0,0,0,0
                                      % End third day
|0,0,0,0
|0,0,0,0
|0,0,0,0
|0,0,0,0
|1,1,1,1
|1,1,1,1
|0,0,0,0
|0,0,0,0
|0,0,0,0
|0,0,0,0
                                     %  End fourth day
|0,0,0,0
|0,0,0,0
|0,0,0,0
|0,0,0,0
|1,1,1,1
|1,1,1,1
|0,0,0,0
|0,0,0,0
|0,0,0,0
|0,0,0,0
                                       %End fifth day
|];

Enrollments= [|1,0,1,0,1        % Exams rows %Students columns              
|1,0,1,0,1
|0,1,0,0,0
|1,0,0,1,0
|0,1,0,0,0
|0,0,1,1,0
|1,0,0,1,0
|0,0,0,0,1
|1,0,0,0,1
|0,0,0,0,1
|0,1,0,0,0
|0,0,0,0,0
|0,1,0,0,1
|0,0,1,0,1
|1,0,1,0,1
|1,0,1,0,1
|0,1,0,0,0
|1,0,0,1,0
|0,1,0,0,0
|0,0,1,1,0
|1,0,0,1,0
|0,0,0,0,1
|1,0,0,0,1
|0,0,0,0,1
|0,1,0,0,0
|0,0,0,0,0
|0,1,0,0,1
|0,0,1,0,1
|1,0,1,0,1
|1,0,1,0,1
|0,1,0,0,0
|1,0,0,1,0
|0,1,0,0,0
|0,0,1,1,0
|1,0,0,1,0
|0,0,0,0,1
|1,0,0,0,1
|0,0,0,0,1
|0,1,0,0,0
|0,0,0,0,0
|0,1,0,0,1
|0,0,1,0,1
|1,0,1,0,1
|1,0,1,0,1
|0,1,0,0,0
|1,0,0,1,0
|0,1,0,0,0
|0,0,1,1,0
|1,0,0,1,0
|0,0,0,0,1
|];

提前致谢

【问题讨论】:

    标签: constraints check-constraints constraint-programming minizinc


    【解决方案1】:

    对于输出部分,以下代码应该可以工作。我只更改了 Day 的日程安排,其余的保持不变。

    output ["\n" ++ "MiniZinc paper: Exams schedule " ++ "\n" ]
    ++
    [
       if t mod 10 = 1 /\ r = 1 then
          "\n\nDay " ++ show(d) ++ " \n"
       else  "" endif ++
       if r=1 then "\n" else " " endif ++
          show(Timetable_exams[t,r])
    | d in 1..Days, t in 1+(d-1)*10..(Slotstime div Days)*d, r in 1..Rooms,
    ]
    ++[ "\n"]++
    [
    "\nExams_Room:   ", show(ExamsRoom), "\n",
    "Exams_Start:  ", show(ExamsStart), "\n",
    ]
    ++["Participants: "]++
    [
    if e=Exams then " " else " " endif ++
       show (sum([bool2int(Enrollments[st,e]>0)| st in 1..Students]))
    |e in 1..Exams
    ];
    

    如果要求用“I”、“II”等对日期进行编号,那么您可以使用日期名称定义一个字符串数组,例如

     array[1..Days] of string: DaysStr = ["I","II","III","IV","V"];
    

    然后在输出循环中使用:

     % ....  
       if t mod 10 = 1 /\ r = 1 then
          "\n\nDay " ++ DaysStr[d] ++ " \n"  % <---
       else  "" endif ++
     % .... 
    

    稍后更新:

    使模型更通用(更小)的另一件事是用这个替换巨大的不可用矩阵(以及使用它的约束):

     set of int: UnavailabilitySlots = {5,6};
    
     % ....
     constraint 
         forall(c in 1..Slotstime, p in 1..Rooms) (
           if c mod 10 in UnavailabilitySlots then 
              Timetable_exams[c,p] = 0
           else 
              true
           endif
      );
    

    还有一条评论:

    原始模型有一个缺陷,它允许超过两天的考试,例如第一天的最后两个小时和第二天的前两个小时。我认为以下额外的(而不是那么漂亮的)约束将解决这个问题。再次使用魔法“10”。

    constraint
       % do not pass over a day limit
       forall(e in 1..Exams) (
            not(exists(t in 1..Exams_duration[e]-1) (
               (ExamsStart[e]+t-1) mod 10 > (ExamsStart[e]+t) mod 10
            ))
       )
     ;
    

    【讨论】:

    • 你的输出比我的聪明!也简洁紧凑!
    • 你喜欢它。注意:Slotstime 的输出和声明中都有 10。也许它应该是一个常数,例如slot_per_day。
    • 知道了!这可能是另一个改进,可以使程序更具可扩展性并且更容易满足自己的目的和需求!
    • 添加了关于如何摆脱不可用矩阵的评论。
    • 简单,高效,现在更短!添加 int: Slots_per_day;在数据 Slotstime=(Slots_per_day)*Days 和 Slots_per_day=10。我们终于有了一个完全定制的模型!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-31
    • 1970-01-01
    相关资源
    最近更新 更多