我目前正试图仅使用clpfd序言库提供的约束来解决这个难题houses,这意味着我无法使用回溯功能!
基本上,我想找出应该建造哪些房屋,以便所有连接之间只有2个距离。
我的输入是一个像[[0,0],[0,3],[2,0],[3,0],[2,1],[3,1],[2,2],[3,3]]
这样的坐标列表,解决方案是:
[
[[0,0],[0,3]],
[[2,0],[3,1]],
[[2,1],[3,0]],
[[2,2],[3,3]]
]
我当前的进度是这个:
connect(Houses):-
%There are only 2 distances and they're different
length(Distances, 2),
all_distinct(Distances),
%One connection per 2 houses (pairs) means half the number of houses as connections
length(Houses, NHouses),
NConnections #= NHouses // 2,
length(Connections, NConnections),
restrictDistances(Connections, Distances), %restrict every connection to have one of the two distances
%All the houses must be connected
append(Connections, ConnectedHouses),
ensureAllConnected(Houses, ConnectedHouses), %table
removeSymmetries(Connections), %avoid symmetries
%flatten list and labeling
append(ConnectedHouses, HousesCoordinates),
labeling([], HousesCoordinates),
write(Connections).
/*
All distances of all connections are one of the two distances
Distance is kept squared to keep it an integer i.e. dist(connection) = dist([[x1, y1], [x2, y2]]) = (x2-x1)^2 + (y2-y1)^2
*/
restrictDistances([], _).
restrictDistances([[[X1, Y1], [X2, Y2]]|Connections], Distances):-
DiffX #= X2 - X1,
DiffY #= Y2 - Y1,
Dis #= DiffX * DiffX + DiffY * DiffY,
% element(Idx, Distances, Dis), %element
member(Dis, Distances), %element
restrictDistances(Connections, Distances).
/*
Ensures all houses are connected
*/
ensureAllConnected([], _).
ensureAllConnected([H|Houses], ConnectedHouses):-
member(H, ConnectedHouses),
% element(_, ConnectedHouses, H),
ensureAllConnected(Houses, ConnectedHouses).
/*
Remove symmetries and connection permutations in final result
*/
removeSymmetries([_]).
removeSymmetries([[[X1, _], [X2, _]], [[X3, Y3], [X4, Y4]]|Connections]):-
X1 #=< X2,
X1 #=< X3,
X3 #=< X4,
removeSymmetries([[[X3, Y3], [X4, Y4]]|Connections]).
最糟糕的部分是此代码有效,但是无法使用谓词member
,因为它使用了回溯功能。是的,谓词element
存在,但是我无法替换它,因为如果替换第一个,则输出是不同的;如果替换第二个,则会出现实例化错误。
答案 0 :(得分:4)
严格来说,该问题未得到充分说明,因为存在多种距离,例如欧几里得距离和哈密顿距离。显然,预期的是欧几里得距离,否则您将为此实例获得多个解决方案。
对于这个难题,考虑使用全局约束编码哪些子任务会很有用。这里有一些提示:
assignment(Xs,Xs)
。 table/2
对(房屋,房屋,距离)关系进行编码。 nvalue/2
进行约束
不同距离的数量。这些是SICStus Prolog中的全局约束。