Time 5, 3, 8, 2, 7, 3, 9, 3, 3, 5, 7
您必须将玩家(使用时间)安排到三个不同的阵雨。获得最佳解决方案。 到目前为止,我的解决方案是:
use_module(library(clpfd)).
shower(S, E, D, Done) :-
D = [5, 3, 8, 2, 7, 3, 9, 3, 3, 5, 7],
R = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
length(D, N),
length(S, N),
length(E, N),
domain(S, 0, 100),
domain(E, 0, 100),
Done in 0..100,
ready(E, Done),
tasks(S, D, E, R, Tasks),
cumulative(Tasks, [limit(3)]),
labeling([minimize(Done)], [Done|S]).
tasks([], [], [], [], []).
tasks([S|Ss], [D|Ds], [E|Es], [R|Rs], [T|Ts]) :-
T = task(S, D, E, R, 0),
tasks(Ss, Ds, Es, Rs, Ts).
ready([], _).
ready([E|Es], Done) :-
Done #>= E,
ready(Es, Done).
如果我运行程序:
?- shower(S,D).
它会打印出来:
D = 19,
S = [0,0,0,3,5,5,8,8,11,14,12]
完成是总时间(最长时间),S是每个任务的开始时间,E是每个任务的结束时间,而D是任务的持续时间。
到目前为止,非常好。
但是现在,我正在努力解决其他问题。确切地说:
1)我怎样才能打印哪个玩家正在使用哪种淋浴?
2)我如何限制一次淋浴才能最多运行四名球员?
我是Prolog的新手,很可能这可能是我写的最后一个节目。到目前为止,我设法做到这一点,但我需要完成这个(你猜它,这是一个任务)。这是我在这门课程上要做的最后一件事,我以前从未做过任何约束逻辑编程。
感谢阅读并最终回复此事!
答案 0 :(得分:3)
好问题,+ 1!
以下是解决问题的一种方法:假设您已经找到满足资源限制的计划。然后,您只需描述必须保留的内容,以便可以按照所需的方式将任务分配给计算机。
例如:
distribution(Starts, Ends, Machines) :-
pairs_keys_values(Pairs, Starts, Ends),
length(Ms0, 4),
maplist(=(0-[]), Ms0),
foldl(task_machines0_machines, Pairs, Ms0, Ms1),
pairs_values(Ms1, Machines0),
maplist(reverse, Machines0, Machines1),
msort(Machines1, Machines).
task_machines0_machines(Start-End, Ms0, [End-[Start|Starts]|Ms1]) :-
Start #>= OccupiedUntil,
select(OccupiedUntil-Starts, Ms0, Ms1),
L #=< 2,
length(Starts, L).
Machines
包含每个计算机的一个列表,其中每个列表依次包含分配给该计算机的任务的开始时间。
我更准确地将这些任务确定为一个简单的练习。
示例用法及其结果:
?- shower(Starts, Ends, _, _), distribution(Starts, Ends, Machines).
Starts = [0, 0, 0, 1, 2, 3, 0],
Ends = [3, 3, 1, 2, 3, 4, 4],
Machines = [[0], [0], [0, 1, 2], [0, 3]] .
让我们看看有多少独特的解决方案,总持续时间为 4 时段,由于资源限制,我们已经知道这是最小的:
?- setof(Ms, Starts^Ends^Ds^(shower(Starts, Ends, Ds, 4),
distribution(Starts, Ends, Ms)),
Mss),
length(Mss, L).
Mss = [[[0], [0, 1], [0, 3], [0, 3]], ...]
L = 14.
这是实际唯一解决方案数量的下限,如果我们考虑到唯一的任务标识符而非开始时间,我们只能计算。
我已经完成了这项工作并找到了 20种来分配受所有约束限制的任务,可以互换使用这些机器:
distributions([
[[1],[2,3],[4,5,6],[7]], [[1],[2,4],[3,5,6],[7]], [[1],[2,5],[3,4,6],[7]],
[[1],[2,6],[3,4,5],[7]], [[1,3],[2],[4,5,6],[7]], [[1,3],[2,4],[5,6],[7]],
[[1,3],[2,5],[4,6],[7]], [[1,3],[2,6],[4,5],[7]], [[1,4],[2],[3,5,6],[7]],
[[1,4],[2,3],[5,6],[7]], [[1,4],[2,5],[3,6],[7]], [[1,4],[2,6],[3,5],[7]],
[[1,5],[2],[3,4,6],[7]], [[1,5],[2,3],[4,6],[7]], [[1,5],[2,4],[3,6],[7]],
[[1,5],[2,6],[3,4],[7]], [[1,6],[2],[3,4,5],[7]], [[1,6],[2,3],[4,5],[7]],
[[1,6],[2,4],[3,5],[7]], [[1,6],[2,5],[3,4],[7]]
]).
答案 1 :(得分:3)
如果您使用cumulatives/[2,3]
约束而不是cumulative/1
约束,那么您将获得为“免费”分配的计算机。
通过使用cumulatives
,每台机器可以获得单独的资源容量。
这表明您使用cumulatives
解决了问题:
:- use_module(library(clpfd)).
:- use_module(library(lists)).
go( Ss, Es, Ms) :-
Ss = [S1, S2, S3, S4,S5,S6,S7], %Starttimes
Es = [E1, E2, E3, E4,E5,E6,E7], %Endtimeds
Ms = [M1, M2, M3, M4,M5,M6,M7], %MachineIds
domain(Ss, 0, 10),
domain(Es, 0, 10),
domain(Ms, 1, 4),
Tasks = [
task( S1, 3, E1, 1, M1 ),
task( S2, 4, E2, 1, M2 ),
task( S3, 1, E3, 1, M3 ),
task( S4, 1, E4, 1, M4 ),
task( S5, 1, E5, 1, M5 ),
task( S6, 1, E6, 1, M6 ),
task( S7, 4, E7, 1, M7 )
],
%All machines has resource capacity = 1
Machines = [
machine( 1, 1 ),
machine( 2, 1 ),
machine( 3, 1 ),
machine( 4, 1 )
],
cumulatives(Tasks, Machines, [bound(upper)] ),
maximum( MaxEndTime, Es ),
%The variables to lable:
append([Ms, Ss ], Vars),
labeling( [minimize(MaxEndTime)], Vars).
启动时,你会得到:
| ?- go( Ss, Es, Ms) .
Ss = [0,0,3,0,1,2,0],
Es = [3,4,4,1,2,3,4],
Ms = [1,2,1,3,3,3,4] ?
如你所见: 任务1分配给机器1,开始时间为0 任务2被分配给机器2,开始时间为0 任务3被分配给具有开始时间3的机器1 。
答案 2 :(得分:1)
我修改了您的代码,因为我使用的是SWI-prolog ......
:- use_module(library(clpfd)).
shower(Durations, NumMachines, Starts, Done) :-
sum_list(Durations, Max),
Done in 0..Max,
maplist(task(Max, Done), Durations, Tasks, Starts),
cumulative(Tasks, [limit(NumMachines)]),
labeling([min(Done)], [Done|Starts]).
task(Max, Done, Duration, task(Start, Duration, End, 1, 0), Start) :-
MaxStart is Max-Duration,
Start in 0..MaxStart,
End #= Start + Duration, %End in 0..Max,
Done #>= End.
也就是说,现在shower / 4需要持续时间和机器数量,并输出开始时间和最小化时间(这应该是适当的术语)。
1 ?- shower([3, 3, 1, 1, 1, 1, 4], 4, S, D).
S = [0, 0, 0, 1, 2, 3, 0],
D = 4 ;
S = [0, 0, 0, 1, 3, 2, 0],
D = 4
...
有很多可能性,修正了下限
?- aggregate(count,S^shower([1, 1, 1, 1, 3, 3, 4], 4, S, 4),N).
N = 348.
打印全部:
?- forall(shower([1, 1, 1, 1, 3, 3, 4], 4, S, 4), writeln(S)).
将机器简单分配给任务:
allocate_machines(Machines, Starts, Durations, Gantt) :-
findall(M-[], member(M, Machines), Pool),
distribute(Starts, Durations, Pool, Gantt).
distribute([], [], Allocated, Allocated).
distribute([S|Ss], [D|Ds], Pool, Allocated) :-
select(M-Duties, Pool, Reduced),
\+ busy(S, Duties),
length(Duties, L), L < 3,
append(Duties, [S/D], Updated),
distribute(Ss, Ds, [M-Updated|Reduced], Allocated).
busy(S, [Sd/Dd|_]) :- S < Sd+Dd, !.
busy(S, [_|Ds]) :- busy(S, Ds).
答案 3 :(得分:0)
@MortenM
我对你的代码进行了一些修改,使得更适合我的限制(基本上,不同的时间用于任务 - 就像我在原始规范中那样,添加第四台机器 - 更重要的是,任务从0时开始,而不是时间1)。代码现在看起来:
go( Ss, Es, Ms) :-
Ss = [S1, S2, S3, S4,S5,S6,S7], %Starttimes
Es = [E1, E2, E3, E4,E5,E6,E7], %Endtimeds
Ms = [M1, M2, M3, M4,M5,M6,M7], %MachineIds
domain(Ss, 0, 20),
domain(Es, 0, 20),
domain(Ms, 1, 10),
%All task has duration = 1
Tasks = [
task( S1, 3, E1, 1, M1 ),
task( S2, 3, E2, 1, M2 ),
task( S3, 1, E3, 1, M3 ),
task( S4, 1, E4, 1, M4 ),
task( S5, 1, E5, 1, M5 ),
task( S6, 1, E6, 1, M6 ),
task( S7, 4, E7, 1, M7 )
],
%All machines has resource capacity = 1
Machines = [
machine( 1, 1 ),
machine( 2, 1 ),
machine( 3, 1 ),
machine( 4, 1)
],
cumulatives(Tasks, Machines, [bound(upper)] ),
maximum( MaxEndTime, Es ),
%The variables to lable:
append([Ms, Ss ], Vars),
labeling( [minimize(MaxEndTime)], Vars).
然而,当我运行它时,结果(正确的结果)是:
?- go(Ss,Es,Ms).
Ss = [0,0,3,3,0,1,0],
Es = [3,3,4,4,1,2,4],
Ms = [1,2,1,2,3,3,4] ?
唯一的问题是该计划并没有给我其他解决方案。这不是唯一的解决方案,但它看起来程序只找到这个。不知道为什么或如何改变它。
非常感谢,你是一名救星。
注意:我在你做出最后的改变之前发了这篇文章:)