如何在答案集编程ASP Clingo中找到倒数第二个值

问题描述

我正在使用答案集编程 (Clingo) 为大学课程时间表建模。要求是每节课必须分配到特定的周、日和开始/结束时间,直到达到总小时数。

一天最多有 8 小时,每节课最少 2 小时。预定的课程也将持续到第 10 周。

week(1..10). time(9,11;11,13;14,16;16,18).  

所以首先我生成了每个分配的课程槽

TotalHours { assigned(Week,Day,Start,End,Course,Teacher) : day(Day),time(Start,End),week(Week) } TotalHours :-
lesson(Course,Teacher,TotalHours).

在那之后,对于其他要求和规则,我需要找到时间表中分配的最后一门课程。我不知道这是否是一个方法,但我找到了解决方

MaxWeek =  #max {Week : assigned(Week,_,_)},MaxDay = #max {Day : assigned(MaxWeek,MaxStart= #max {Start : assigned(MaxWeek,MaxDay,assigned(_,_).

我是 ASP 的新手,到目前为止,我找不到找到其他时间表要求所需的时间表(周、日、开始、结束)中分配的课程的倒数第二节的好方法。>

举个例子

assigned(1,Monday,9,11,History,John),assigned(1,Tuesday,13,Math,Smith),assigned(4,16,18,assigned(5,John)

我想找到历史的倒数第二课

已分配(4,18)

非常感谢任何提示解决方

解决方法

考虑使用第二个赋值谓词(具有不同的元数)更绝对,例如:

assigned((Week-1)*7*24+Day+Start,End,Course,Teacher) :- assigned(Week,Day,Start,Teacher).

现在您只有一个字段,它在所有作业中完全排序,即自年初以来的总小时数。

要找到最后的课程,最后的聚合表现非常糟糕,可以使用链接约束进行优化:

auxLastCourse(C,T) :- assigned(T,_,C,_).
auxLastCourse(C,T-1) :- auxLastCourse(C,T),T > 0.
lastCourse(C,T) :- auxLastCourse(C,not auxLastCourse(C,T+1).

另请注意,在您的示例中,夜间没有任何课程,因此可以通过不那么细粒度和明确表示每小时来进一步优化,但可能只是在可能的时间表中实际发生的小时数。这意味着在数周、数天和数小时内用明确的下一个关系替换辅助代码中的 T-1。目前我只是懒得添加这样的东西。

对于倒数第二个课程,您可以做完全相同的事情:

auxSecondLastCourse(C,_),not lastCourse(C,T).
auxSecondLastCourse(C,T-1) :- auxSecondLastCourse(C,T > 0.
secondLastCourse(C,T) :- auxSecondLastCourse(C,not auxSecondLastCourse(C,T+1).

PS:请注意,我假设您的天数是 0..6,而不是您示例中的单词,我相信您会弄清楚如何使用另一个谓词来翻译它们。

PPS:我没有测试代码,因为你没有提供 MWE。