(Prolog) 检查一个列表是否可以分成 2 个总和相等的子列表
(Prolog) Check if a list can be split into 2 sub-lists that have equal sums
我正在使用 Prolog 来尝试检查是否可以将列表拆分为 2 个 子列表(子数组),它们的总和相等。
以下应该成功:[1,2,3,6], [2,1,1], [0], [1,1,2]
以下应该失败:[1,4,8]、[1,3,2]、[2,2,1,1]
我相信我的程序正在创建 子序列 而不是 子列表 。这会导致类似于 [1,3,2] 和 [2,2,1,1] 的查询在应该失败的时候成功。
在查询 [1,3,2] 的示例中,它 return 为真,因为子序列 [1,2] 和 [3] 的总和相等。那不应该被允许。相反,[1,3,2] 应该分成子列表 [1]/[3,2] 和 [1,3]/[2]。因此,它应该失败。
我不确定如何将 subL 谓词修改为 return 子列表而不是子序列。
这是我目前的情况:
split([]).
split([0]).
split([H|T]) :-
subL([H|T], LEFT, RIGHT),
sum(LEFT, SUM1),
sum(RIGHT, SUM2),
SUM1=SUM2.
subL([],[],[]).
subL([H|T], [H|T2], X) :-
subL(T, T2, X).
subL([H|T], X, [H|T2]) :-
subL(T, X, T2).
sum([H|T], SUM1) :-
sum(T, SUM2),
SUM1 is SUM2 + H.
sum([H], SUM1) :-
H = SUM1.
如有任何帮助,我们将不胜感激。谢谢
您可以使用 append
将列表拆分为不同的列表。确实:
?- append(L, R, [1,2,3,6]).
L = [],
R = [1, 2, 3, 6] ;
L = [1],
R = [2, 3, 6] ;
L = [1, 2],
R = [3, 6] ;
L = [1, 2, 3],
R = [6] ;
L = [1, 2, 3, 6],
R = [] ;
false.
所以你可以写一个谓词:
split(X) :-
append(L, R, X),
sum(L, <b>S</b>),
sum(R, <b>S</b>).
这里我们检查左右子列表的总和是否相同S
。但是,您略微需要更改 sum/2
谓词,使空列表的总和也为 0
。我把它留作练习。
以上不是很有效,因为它需要 O(n2) 时间。您可以通过首先计算整个列表的总和使其成为线性,然后创建一个遍历列表的谓词,每次跟踪左侧元素的总和,以及右侧剩余的总和。我认为通过首先以 "naive" 方式解决它,您可能会发现更容易将其作为改进来实施。
我正在使用 Prolog 来尝试检查是否可以将列表拆分为 2 个 子列表(子数组),它们的总和相等。
以下应该成功:[1,2,3,6], [2,1,1], [0], [1,1,2]
以下应该失败:[1,4,8]、[1,3,2]、[2,2,1,1]
我相信我的程序正在创建 子序列 而不是 子列表 。这会导致类似于 [1,3,2] 和 [2,2,1,1] 的查询在应该失败的时候成功。
在查询 [1,3,2] 的示例中,它 return 为真,因为子序列 [1,2] 和 [3] 的总和相等。那不应该被允许。相反,[1,3,2] 应该分成子列表 [1]/[3,2] 和 [1,3]/[2]。因此,它应该失败。
我不确定如何将 subL 谓词修改为 return 子列表而不是子序列。
这是我目前的情况:
split([]).
split([0]).
split([H|T]) :-
subL([H|T], LEFT, RIGHT),
sum(LEFT, SUM1),
sum(RIGHT, SUM2),
SUM1=SUM2.
subL([],[],[]).
subL([H|T], [H|T2], X) :-
subL(T, T2, X).
subL([H|T], X, [H|T2]) :-
subL(T, X, T2).
sum([H|T], SUM1) :-
sum(T, SUM2),
SUM1 is SUM2 + H.
sum([H], SUM1) :-
H = SUM1.
如有任何帮助,我们将不胜感激。谢谢
您可以使用 append
将列表拆分为不同的列表。确实:
?- append(L, R, [1,2,3,6]).
L = [],
R = [1, 2, 3, 6] ;
L = [1],
R = [2, 3, 6] ;
L = [1, 2],
R = [3, 6] ;
L = [1, 2, 3],
R = [6] ;
L = [1, 2, 3, 6],
R = [] ;
false.
所以你可以写一个谓词:
split(X) :-
append(L, R, X),
sum(L, <b>S</b>),
sum(R, <b>S</b>).
这里我们检查左右子列表的总和是否相同S
。但是,您略微需要更改 sum/2
谓词,使空列表的总和也为 0
。我把它留作练习。
以上不是很有效,因为它需要 O(n2) 时间。您可以通过首先计算整个列表的总和使其成为线性,然后创建一个遍历列表的谓词,每次跟踪左侧元素的总和,以及右侧剩余的总和。我认为通过首先以 "naive" 方式解决它,您可能会发现更容易将其作为改进来实施。