我正在努力解决以下问题,使用prolog将一个集合划分为n个子集。
所以例如,我给程序输入:X = [1,2,3,4],N = 3,我得到
Res = [[1,2], [3], [4]]
Res = [[1,3], [2], [4]]
Res = [[1,4], [2], [3]]
Res = [[2,3], [1], [4]]
Res = [[2,4], [1], [3]]
Res = [[3,4], [1], [2]]
或者我作为输入:X = [1,2,3,4],N = 2,我得到
Res = [[1,2], [3,4]]
Res = [[1,3], [2,4]]
Res = [[1,4], [2,3]]
Res = [[1,2,3], [4]]
Res = [[1,2,4], [3]]
Res = [[1,3,4], [2]]
Res = [[2,3,4], [1]]
答案 0 :(得分:4)
这个答案延伸了 @lurker's previous answer具有其他(冗余)约束。
使用dcg我们定义了以下辅助非终端:
same_length([]) --> []. % DCG-style same_length/2 same_length([_|Es]) --> [_], same_length(Es). same_length1([_|Es]) --> [_], same_length(Es). same_lengths1([]) --> []. same_lengths1([Es|Ess]) --> same_length1(Es), same_lengths1(Ess).
我们通过预先添加phrase/2
目标来利用这些DCG:
list_partitionedNU(Es, Xss) :- phrase(same_lengths1(Xss), Es), list_partitioned(Es, Xss).
对于一些普通的测试案例,我们仍然可以得到合理的答案吗?
?- list_partitionedNU([a,b,c], Xss). Xss = [[a],[b],[c]] ; Xss = [[a],[b,c]] ; Xss = [[a,b],[c]] ; Xss = [[a,c],[b]] ; Xss = [[a,b,c]] ; false.
当然看起来对我好。
接下来,让我们谈谈全面终止。像list_partitioned(Es, [[a,b,c]])
这样的目标不会普遍终止 - 即使它们是微不足道的。 list_partitionedNU/2
解决了这个问题:
?- list_partitioned(Es, [[a,b,c]]). Es = [a,b,c] ; NONTERMINATION ?- list_partitionedNU(Es, [[a,b,c]]). Es = [a,b,c] ; false. % terminates universally
这些额外的约束可以大大加快一些查询。
使用SICStus Prolog 4.4.0:
| ?- use_module(library(between), [numlist/3]). yes | ?- numlist(1, 14, _Es), length(_Xss, 10), member(P_2, [list_partitioned,list_partitionedNU]), call_time((call(P_2,_Es,_Xss), false ; true), T_msec). P_2 = list_partitioned , T_msec = 29632 ? ; P_2 = list_partitionedNU, T_msec = 600 ? ; % 40x faster no
好的!当然,加速取决于所用列表的实际长度...... YMMV:)
答案 1 :(得分:2)
问题已在这个问题中得到解决:All Partitions of a List In Prolog。只需在“Prolog分区集”上进行Google搜索即可轻松找到。
然后你可以用length/2
:
partitions_of_length(List, N, Partition) :-
length(Partition, N), list_partitioned(List, Partition).
| ?- partitions_of_length([a,b,c,d], 2, L).
L = [[a,b,c],[d]] ? ;
L = [[a,b,d],[c]] ? ;
L = [[a,b],[c,d]] ? ;
L = [[a,c,d],[b]] ? ;
L = [[a,c],[b,d]] ? ;
L = [[a,d],[b,c]] ? ;
L = [[a],[b,c,d]] ? ;
no
| ?-
我们通过首先限制长度来优化性能。下面在SWI Prolog中说明了约束之后与之前的长度之间的差异:
:- use_module(library(statistics)).
6 ?- time((list_partitioned([a,b,c,d], P), length(P, 2))).
% 18 inferences, 0.000 CPU in 0.000 seconds (85% CPU, 1580195 Lips)
P = [[a, b, c], [d]] ;
% 12 inferences, 0.000 CPU in 0.000 seconds (88% CPU, 1059696 Lips)
P = [[a, b, d], [c]] ;
% 10 inferences, 0.000 CPU in 0.000 seconds (86% CPU, 900414 Lips)
P = [[a, b], [c, d]] ;
% 19 inferences, 0.000 CPU in 0.000 seconds (88% CPU, 1624070 Lips)
P = [[a, c, d], [b]] ;
% 10 inferences, 0.000 CPU in 0.000 seconds (86% CPU, 1021555 Lips)
P = [[a, c], [b, d]] ;
% 19 inferences, 0.000 CPU in 0.000 seconds (87% CPU, 1665060 Lips)
P = [[a, d], [b, c]] ;
% 19 inferences, 0.000 CPU in 0.000 seconds (87% CPU, 1661420 Lips)
P = [[a], [b, c, d]] ;
% 37 inferences, 0.000 CPU in 0.000 seconds (90% CPU, 2382639 Lips)
false.
7 ?- time((length(P, 2), list_partitioned([a,b,c,d], P))).
% 13 inferences, 0.000 CPU in 0.000 seconds (89% CPU, 1175832 Lips)
P = [[a, b, c], [d]] ;
% 6 inferences, 0.000 CPU in 0.000 seconds (83% CPU, 742023 Lips)
P = [[a, b, d], [c]] ;
% 6 inferences, 0.000 CPU in 0.000 seconds (85% CPU, 848896 Lips)
P = [[a, b], [c, d]] ;
% 9 inferences, 0.000 CPU in 0.000 seconds (84% CPU, 1210328 Lips)
P = [[a, c, d], [b]] ;
% 6 inferences, 0.000 CPU in 0.000 seconds (82% CPU, 828386 Lips)
P = [[a, c], [b, d]] ;
% 9 inferences, 0.000 CPU in 0.000 seconds (84% CPU, 1215723 Lips)
P = [[a, d], [b, c]] ;
% 9 inferences, 0.000 CPU in 0.000 seconds (90% CPU, 697999 Lips)
P = [[a], [b, c, d]] ;
% 10 inferences, 0.000 CPU in 0.000 seconds (86% CPU, 991277 Lips)
false.
如果要修改上面链接中的代码来约束列表的长度,最好的方法可能是在执行任何其他操作之前将length/2
调用放在谓词中,但行为是相同的以上。