[英]Prolog: Comparing Lists from Lists of Lists
我现在花了很长时间试图弄清楚我的错误是什么,但我做不到。
任务:我们必须弄清楚如何以列表列表的形式找到包含 9 个元素的列表的三个排列。 每个列表列表应包含三个子列表,每个子列表包含三个元素。 但是不允许任何元素与两个不同子列表中的另一个元素在一起。
以下 output 对于三个排列 A、B、C 和给定的 List= [1,2,3,4,5,6,7,8,9] 可以是:
predicate(A, B, C , [1,2,3,4,5,6,7,8,9]).
A = [[1,2,3],[4,5,6],[7,8,9]],
B = [[1,4,7],[2,5,8],[3,6,9]],
C = [[1,5,9],[2,6,7],[3,4,8]].
到目前为止我的代码(首先是我的辅助谓词):
将列表拆分为列表列表( N 始终为 3 ):
split_list(List, N, Splitted_List) :-
split_helper(List, N, [], Splitted_List).
split_helper([], _, Acc, Acc).
split_helper(List, N, Acc, Splitted_List) :-
my_append(H, T, List),
my_length(H, N),
split_helper(T, N, [H|Acc], Splitted_List).
一个可能的查询:
split_list([1,2,3,4,5,6,7,8,9], 3, X).
X = [[1,2,3],[4,5,6],[7,8,9]].
检查列表列表的所有子列表是否最多包含一个相同的元素:
max_one_common_element(List1, List2) :-
max_one_common_element(List1, List2, 0).
max_one_common_element([], _, Count) :-
Count =< 1.
max_one_common_element([H|T], List2, Count) :-
(my_member(H, List2) ->
NewCount is Count + 1,
max_one_common_element(T, List2, NewCount)
;
max_one_common_element(T, List2, Count)
).
一个可能的查询:
max_one_common_element([[1,2,3],[4,5,6],[7,8,9]], [[1,4,7],[2,5,8],[3,6,9]]).
True.
要更改子列表的顺序,以便进行比较(稍后很重要):
swap_lists(List, Result):-
select(Selected, List, Rest),
append(Rest, [Selected], Result).
一个可能的查询:
swap_list([[1,2,3],[4,5,6],[7,8,9]], X).
X = [[4,5,6],[7,8,9],[1,2,3]].
我的主要谓词,它实例化了 A、B 和 C。让我产生问题的是 C,A 和 B 已正确实例化。
我正在考虑采用输入列表的所有排列并检查 max_one_common_element/2 每个子列表是否最多有一个公共元素。 由于 max_one_common_element/2 只能检查当前索引处的两个列表(例如 [[1,2],[3,4]], [[3,4],[1,2]] 会返回 True,即使这是错误的)我的想法是两次更改 A 和 B 的子列表的顺序,并在第一次和第二次更改后再次检查 C,因此应覆盖 A 和 B 的所有 3 个子列表。
main_predicate(A, B, C, List):-
/* instantiates A as the input list but seqmented */
split_list(List, 3 , A),
/* instantiates B as a permutation of A, taking every nth element in a sublist*/
%This part is unimportant since it works properly
/* instantiates C as a permutation from the input list, test that each Sub-List contains at most one same element */
permutation(List, Permuted),
split_list(Permuted, Size, Dessert),
max_one_common_element(A, C),
max_one_common_element(A, C),
/* first swap A and B two times */
swap_lists(A, A1),
swap_lists(A1, A2),
swap_lists(B, B1),
swap_lists(B1, B2),
/* Check again with C */
max_one_common_element(A1, C),
max_one_common_element(A2, C),
max_one_common_element(B1, C),
max_one_common_element(B2, C).
当我查询:
predicate(A, B ,C, [1,2,3,4,5,6,7,8,9] ).
My output is:
A = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] ,
B = [[1, 4, 7], [2, 5, 8], [3, 6, 9]] ,
C = [[7, 8, 9], [4, 5, 6], [1, 2, 3]] .
Prolog 只是似乎没有考虑 max_one_common_element/2 的每一次调用。 由于删除一些似乎改变了 output,但在我看来,我已经考虑了所有情况,一切都应该没问题。 我也考虑过更改 max_one_common_element/2,但没有任何效果。 非常感谢您的提前帮助。
控制回溯很有趣(对所有解决方案子列表执行member_count_inc_le
):
:- dynamic used/2.
list_perm3(L, P) :-
retractall(used(_, _)),
list_perm3_loop(L, P).
list_perm3_loop(L, P) :-
% Keeping backtracking to this top-level
(list_perm3_(L, P) -> true ; !, fail).
list_perm3_loop(L, P) :-
list_perm3_loop(L, P).
list_perm3_(L, P) :-
length(P, 3),
perm3_lists(P, L),
assert_used(P).
% Add the new solution via assert
assert_used([]).
assert_used([H|T]) :-
% Assert the used pairs, to prevent reuse
forall(
( select(E1, H, H0),
member(E2, H0)
),
assert(used(E1, E2))
),
assert_used(T).
perm3_lists([], []).
perm3_lists([H|T], L) :-
perm3(L, H, R),
perm3_lists(T, R).
perm3(L, P, R) :-
length(P, 3),
perm3_(P, L, [], R).
perm3_([], R, _, R).
perm3_([H|T], L, P, R) :-
select(H, L, L0),
comb_available(P, H),
perm3_(T, L0, [H|P], R).
comb_available([], _).
comb_available([H|T], E) :-
\+ used(E, H),
comb_available(T, E).
swi-prolog 中的结果:
?- list_perm3([1,2,3,4,5,6,7,8,9], P).
P = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] ;
P = [[1, 4, 7], [2, 5, 8], [3, 6, 9]] ;
P = [[1, 5, 9], [2, 6, 7], [3, 4, 8]] ;
P = [[1, 6, 8], [2, 4, 9], [3, 5, 7]] ;
false.
我设法想出了自己的解决方案:
make_dessert(Starter, Main, Dessert, List_of_Persons, Size):-
permutation(List_of_Persons, Permuted),
split_list(Permuted, Size, Dessert),
at_most_one_common(Starter, Dessert),
at_most_one_common(Main, Dessert).
split_list(List, N, Splitted_List) :-
split_helper(List, N, [], Splitted_List).
split_helper([], _, Acc, Acc).
split_helper(List, N, Acc, Splitted_List) :-
append(H, T, List),
length(H, N),
split_helper(T, N, [H|Acc], Splitted_List).
at_most_one_common([], _).
at_most_one_common([H|T], List2) :-
check_list(H, List2),
at_most_one_common(T, List2).
check_list(_, []).
check_list(X, [H|T]) :-
intersection(X, H, Z),
length(Z, L),
L =< 1,
check_list(X, T).
我忘了说,我会因为将推理保持在最低水平而获得加分。 由于我的程序不如@brebs 的程序高效,我非常感谢您提供一些建议来降低这些。 我可能也在考虑稍后开始关于这个案例的新问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.