我被赋予了使用prolog解决难题的任务。
作为prolog的初学者,在过去的几个小时里刚刚阅读了几本关于prolog的在线教程,我不知道如何开始这个...
这个难题规模要大得多,并且有更多限制,但我会在这里简化它,因为我只是想得到这个想法,以便我可以稍后进行扩展。
这个谜题是这样的: 您需要为本周的2名员工A和B安排轮班。(包括周末) 规则:
软约束:
图表:
|--------|--------|--------|---------|-----------|----------|--------|----------|
| | Sunday | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday |
|--------|--------|--------|---------|-----------|----------|--------|----------|
| A | | | | | | | |
|--------|--------|--------|---------|-----------|----------|--------|----------|
| B | | | | | | | |
|--------|--------|--------|---------|-----------|----------|--------|----------|
如何安排这样才能达到最高点?
一种可能的解决方案(有几种)将是:
|--------|--------|--------|---------|-----------|----------|--------|----------|
| | Sunday | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday |
|--------|--------|--------|---------|-----------|----------|--------|----------|
| A | | | X | X | | | X |
|--------|--------|--------|---------|-----------|----------|--------|----------|
| B | X | X | | | X | X | |
|--------|--------|--------|---------|-----------|----------|--------|----------|
我们可以获得的最大值是5分。因为没有解决方案可以在满足所有规则的同时获得7分的满分。
我的问题:
提前致谢!
答案 0 :(得分:2)
Plain Prolog可能不是这里的最佳选择。这些问题最容易使用0/1整数编程建模,并使用IP或有限域求解器求解,这是几个增强的Prolog所提供的。这是ECLiPSe中的解决方案(免责声明:我是合作开发人员)。软约束通过目标函数处理。
:- lib(ic).
:- lib(ic_global_gac).
:- lib(branch_and_bound).
schedule(Points, As, Bs) :-
As = [_ASu,_AMo, ATu,_AWe, ATh,_AFr,_ASa],
Bs = [_BSu,_BMo,_BTu, BWe,_BTh,_BFr,_BSa],
As :: 0..1,
Bs :: 0..1,
( foreach(A,As), foreach(B,Bs) do A+B #= 1 ), % Rule 1
ATu = 1, % Rule 2
sequence(0, 2, 3, As), % 0..2 out of 3, Rule 3
sequence(0, 2, 3, Bs),
Points #= 2*ATh + 5*(1-BWe), % Soft
Cost #= -Points,
append(As, Bs, ABs),
minimize(labeling(ABs), Cost).
?- schedule(P, As, Bs).
P = 5
As = [0, 0, 1, 1, 0, 0, 1]
Bs = [1, 1, 0, 0, 1, 1, 0]
Yes (0.03s cpu)
答案 1 :(得分:2)
在Prolog中,对于简单的问题,我们可以尝试应用一个简单的模式',简单的generate and test,其简单性很有趣。我们只是'提供适当的域生成器和测试。
generate(D0, D) :-
length(D0, DL),
length(D, DL),
maplist(dom_element, D).
dom_element(a).
dom_element(b).
test(D, Score, D) :-
D = [_Sunday, _Monday, Tuesday, Wednesday, Thursday, _Friday, _Saturday],
% 1. In a single day, either A or B (but not both) must be working
% Here True by construction
% 2. A must work on Tuesday
Tuesday = a,
% 3. no one can work continuously for more than 2 days
no_more_than_2(D),
% soft 1. A prefers to work on Thursday (add 2 points if A works on Thursday )
( Thursday = a -> S1 is 2 ; S1 is 0 ),
% soft 2. B dislike to work on Wednesday (add 5 points if B doesn't work on Wednesday)
( Wednesday \= b -> S2 is 5 ; S2 is 0 ),
Score is S1 + S2.
% edit: jshimpfs suggestion, beside being much better, highlights a bug
no_more_than_2(D) :-
nth0(I, D, E),
length(D, L),
J is (I+1) mod L,
nth0(J, D, E),
K is (J+1) mod L,
nth0(K, D, E),
!, fail.
no_more_than_2(_).
solve(D0, Best) :-
D0 = [sun,mon,tue,wed,thu,fri,sat],
setof(Score/Sol, D^(generate(D0, D), test(D, Score, Sol)), All),
last(All, Best).
试验:
?- solve(_,L).
L = 5/[b, b, a, a, b, b, a].