我决定学习prolog只是为了好玩,我正在看一些视频教程。我也在互联网上搜索了一些试图解决的问题,但是找不到解决这个问题的方法 我能够在纸上解决这个难题,但我无法将其传递给代码。
问题:
我有8名候选人(Lia,Mel,Nanda,Olga,Rute,Sara,Tina,Pilar)。
他们将在周一至周五的8:00和9:00进行测试。
我有一些规则,如:
Sara将于周三9点接受测试 没有女孩将在周三8点接受测试 皮拉尔已经在南达之前进行了测试 Olga将在Mel的同一天进行测试 如果Lia在任何一天的8天进行测试,那么Rute必须在不同的日子进行8次测试。
我不希望完整的解决方案,我只是想从此处获得一些帮助。
我试图写点东西但没有成功。
% Facts %
candidate(lia).
candidate(mel).
candidate(nanda).
candidate(olga).
candidate(pilar).
candidate(rute).
candidate(sara).
candidate(tina).
day(monday).
day(tuesday).
day(wednesday).
day(thursday).
day(friday).
time(8).
time(9).
/*Sara HAS TO be tested on Wednesday at 9*/
tested_on(sara, wednesday, 9).
/*No test will happen on Wednesday at 8*/
no_test(X, wednesday, 8) :- X == none.
我甚至试图建立一个struct
cand(
sara,
date(wednesday, 9)
).
之后我的程序必须回答一些问题:
从星期一到星期五,哪些候选人将在8:00进行测试?
我的主要想法是开始编写规则和事实然后我会完成测试每个规则的所有规则。但我甚至不能写facts
和rules
权利......
答案 0 :(得分:4)
Prolog是一种声明性语言。专注于对每个解决方案的内容的清晰描述。 Prolog系统将为您完成剩下的工作。不要说:"我已经完成了测试每个规则的所有规则"。更好的说法:" 我陈述了适合每个解决方案的属性。"这是因为,当您完成后,您的谓词可用于多个方向:是的,您可以使用它来测试给定的解决方案。但是,您也可以使用它来生成解决方案,并在可能的情况下完成部分填充的计划。
开始于:
schedule(S) :- ...
如下所示:S
是一个时间表,如果 ....现在,填写点:在任何有效的时间表中有哪些属性?这些是您的任务中给出的约束,在Prolog中声明为目标。
如您所愿,我不会给您一个完整的解决方案,但有一些提示可以帮助您入门。我正在使用CLP(FD)约束来声明性地陈述所有要求。该代码在SICStus,SWI,YAP,GNU Prolog和其他几个系统中运行,最多只需稍作修改。
首先,为了表示可用的时隙,我使用整数0..9。具体来说,我使用:
Monday Tuesday Wednesday Thursday Friday
8:00: 0 2 4 6 8
9:00: 1 3 5 7 9
例如,星期四9:00用整数7
表示。
每个候选者都是一个有限域变量,表示候选人被分配的时间段。
我将计划表示为时间列表,每个候选人一个,按任务说明中的顺序列出。
仅使用CLP(FD)谓词对指定的约束进行编码。查看Prolog系统的文档,了解这些谓词的含义。例如,对于SICStus Prolog,请查看membership constraints和arithmetic constraints。同样适用于其他系统。
这是一个开始:
:- use_module(library(clpfd)).
schedule(Vars) :-
Vars = [Lia,Mel,Nanda,Olga,Rute,Sara,_Tina,Pilar],
all_different(Vars),
Vars ins 0..9,
Sara #= 5,
maplist(#\=(4), Vars),
Pilar #< Nanda.
如您所见,这与任务描述中出现的约束密切对应。例如,Sara只能在星期三9:00安排,并且根据上表,此特定时隙对应于整数5
,变量Sara
表示在哪个时隙萨拉计划。因此,我们陈述约束Sara #= 5
。同样,没有人可以在星期三的8:00安排。此时间段对应于整数4
,因此我们声明约束maplist(#\=(4), Vars)
,当且仅当Vars
中的每个变量不相等时才为真((#\=)/2
)至4
。
我将编码最后两个约束作为练习留给你。尝试很好地和紧凑地编码它们。
具有编码约束的示例解决方案:
?- Vs = [Lia,Mel,Nanda,Olga,Rute,Sara,Tina,Pilar], schedule(Vs), label(Vs).
Vs = [0, 1, 3, 7, 6, 5, 8, 2],
Lia = 0,
Mel = 1,
Nanda = 3,
Olga = 7,
Rute = 6,
Sara = 5,
Tina = 8,
Pilar = 2 .
请注意,巧合的是,这甚至满足了我们尚未明确编码的最后一个约束。
答案 1 :(得分:2)
为了简化日期比较,可以方便地进行少量更改:
candidate(1,lia).
candidate(2,mel).
candidate(3,nanda).
candidate(4,olga).
candidate(5,rute).
candidate(6,sara).
candidate(7,tina).
candidate(8,pilar).
day(1,monday).
day(2,tuesday).
day(3,wednesday).
day(4,thursday).
day(5,friday).
然后我们可以将解决方案表示为对(Date,Time)
的列表,其中列表中的位置代表女孩:
solution(Dom) :-
Dom = [
(D1,T1),
(D2,T2),
...
(D8,T8)
],
dom(Dom),
...
域名生成有点棘手:我们必须得到所有不同的Day,Time对。第一种低效的方法
dt((D,T)) :- day(D,_),time(T).
dom([]).
dom([E|R]) :- dt(E), dom(R), \+ memberchk(E, R).
?- length(L,6),time(aggregate(count,so:(L^dom(L)),N)).
% 10,044,119 inferences, 3.188 CPU in 3.190 seconds (100% CPU, 3150577 Lips)
L = [_G6035, _G6038, _G6041, _G6044, _G6047, _G6050],
N = 151200.
虽然这种替代方案更快
dom([E]) :- dt(E).
dom([E|R]) :- dom(R), dt(E), \+ memberchk(E, R).
?- length(L,6),time(aggregate(count,so:(L^dom(L)),N)).
% 952,236 inferences, 0.567 CPU in 0.567 seconds (100% CPU, 1680621 Lips)
L = [_G6041, _G6044, _G6047, _G6050, _G6053, _G6056],
N = 151200.
(dom / 1适用于任何长度,我选择6来举例说明......)
现在可以表达约束,例如
% Sara HAS TO be tested on Wednesday at 9.
day(D6, wednesday), T6 = 9,
约束
星期三8点没有女孩接受测试。
可能很棘手:这意味着(3,8)
对不能出现在Dom中。
但是使用if / then / else构造变得容易。
如果您需要更多线索,请告诉我。