Prolog中的不同素数分区
我需要列举所有将给定数字n划分为一个或多个不同素数之和的方法,a+b+…+我在序言中 例如: 给定一个整数n,程序应将适当的和写入标准输出。例如,如果n=20,程序可能会打印Prolog中的不同素数分区,prolog,computer-science,primes,clpfd,Prolog,Computer Science,Primes,Clpfd,我需要列举所有将给定数字n划分为一个或多个不同素数之和的方法,a+b+…+我在序言中 例如: 给定一个整数n,程序应将适当的和写入标准输出。例如,如果n=20,程序可能会打印 2 + 5 + 13 2 + 7 + 11 3 + 17 7 + 13 n可以是任何数字,并且对运行时没有限制 以下是我所拥有的: partition(N, _, []) :- N = 0. partition(N, [], _) :- fail. partition(N, [IH|IT], [OH|OT]) :-
2 + 5 + 13
2 + 7 + 11
3 + 17
7 + 13
n可以是任何数字,并且对运行时没有限制
以下是我所拥有的:
partition(N, _, []) :- N = 0.
partition(N, [], _) :- fail.
partition(N, [IH|IT], [OH|OT]) :-
N =< 0, fail;
N >= IH, M is N-IH, OH = IH,
partition(M, [IH|IT], OT).
partition(N, [_|IT], Output) :-
N =< 0, fail;
partition(N, IT, Output).
partition(N, Output) :-
generatePrime(N,L),
partition(N, L, Output).
generatePrime(1, []) :- !.
generatePrime(N, X) :-
not(isPrime(N)), !,
Z is N-1,
generatePrime(Z,X).
generatePrime(N, [N | X]) :-
Z is N-1,
generatePrime(Z,X).
isPrime(2).
isPrime(P) :-
P > 2,
isDivisible(P, P-1).
isDivisible(P,X) :-
X > 1,
P mod X =\= 0,
isDivisible(P, X-1).
isDivisible(_, X) :-
1 is X.
分区(N,,[]):-N=0。
分区(N,[],\u1):-失败。
分区(N[IH|IT],[OH|OT]):-
N=<0,失败;
N>=IH,M是N-IH,OH=IH,
分区(M[IH | IT],OT)。
分区(N,[[u124; IT],输出):-
N=<0,失败;
分区(N,IT,Output)。
分区(N,输出):-
生成时间(N,L),
分区(N,L,输出)。
GenerateTime(1,[]):-!。
GenerateTime(N,X):-
不是(iPrime(N))!,
Z是N-1,
生成时间(Z,X)。
GenerateTime(N[N|X]):-
Z是N-1,
生成时间(Z,X)。
iPrime(2)。
iPrime(P):-
P>2,
可分(P,P-1)。
可分(P,X):-
X>1,
P mod X=\=0,
可分(P,X-1)。
可分(X,X):-
1是X。
目前,我尝试运行以下内容:
[?-分区(5,X)
我得到了[5]和[3,2]的重复提示。当我使用n=20这样的大数字时,还有另一类问题,因为我得到了类似[2,2,2,2,2,2,2,2]这样的重复素数提示
我对prolog非常陌生,我相信可能有一种更简单的方法来解决这个问题,但我不确定我在代码中遇到了什么问题。你的不太了解
更大的问题是您调用分区/3的方式
partition(5, generatePrime(5,Y), X)
partition/3
希望第二个学期有一个列表,而不是generateTime(5,Y)
我建议您添加一个分区/2
,如下所示
partition(N, Output) :-
generatePrime(N, L),
partition(N, L, Output).
并调用此版本的分区
partition(5, X)
还有其他错误,因为此调用返回相同响应的时间更长(返回,在X
,[5]
四次和[3,2]
两次)
我会看一看,看我是否发现了问题
---编辑---
很抱歉,我在理解带有剪切(!
)、失败(;
)和或(;
)的序言代码时遇到了大问题
我想这是我的问题
我用以下方式修改了您的分区/3
partition(0, _, []).
partition(N, [H | It], [H | Ot]) :-
N >= H,
M is N-H,
partition(M, [H | It], Ot).
partition(N, [_ | It], O) :-
N > 0,
partition(N, It, O).
这应该避免重复列表
如果您希望避免在同一列表中重复素数(如果您不接受8的[3,3,2]
或[2,2,2]
,因为素数重复),那么您应该避免在以下对分区/3
的调用中重复使用H
(IH
)
我的意思是下面的条款
partition(N, [H | It], [H | Ot]) :-
N >= H,
M is N-H,
partition(M, [H | It], Ot).
应该成为
partition(N, [H | It], [H | Ot]) :-
N >= H,
M is N-H,
partition(M, It, Ot).
这是一个相对有效的答案,在SWI Prolog中使用
您需要:-在程序开始时使用_模块(库(clpfd))。
主谓词:partition/2
这个谓词可以用一种非常简单的方式来描述:
partition(N,Z) :-
findall(P, (P in 2..N, prime(P)), L),
findall(S, ordered_subset_sum(L, S, N), Z).
简而言之:在[2,N]
中查找所有的p
,使它们成为素数。我们将这些素数存储在列表L
中
然后,我们使用谓词ordered_subset_sum/3
检查对L
的有序子集S
求和是否会产生N
。我们将有效子集存储在Z
中,这是我们的输出
ordered\u subset\u sum/3
- 基本情况:空列表只能生成空子集;空子集的元素之和为
0
- 第二条:我们将列表的开头
H
保留在子集中;因此,我们想要达到的N
的总和减少H
,导致M
。如果M
为负数,那么我们已经知道子集不能和到N
,它太大了
- 第三条:我们忽略列表的头部,允许生成子集
prime/1
如果愿意,您可以重用谓词isPrime
,例如:
prime(N) :-
indomain(N),
isPrime(N).
但我建议使用一种更有效的素数检查算法。我建议使用下面的算法,它远不是最优的,但比你的算法效率更高。它检查你的数的素数分解是否只有一个元素(只有素数)。你也可以看一下
谢谢你的回答。我会相应地编辑这个问题。我还注意到,当我使用像20这样的数字时,我有你所说的重复答案,但也有像[2,2,2,2,2,2,2,2,2,2]这样不明显的素数答案。@Ganda-修改了我的anser以显示如何避免重复(列表中的素数列表)。
prime(N) :-
indomain(N),
isPrime(N).
prime(N) :-
prime_decomposition(N,[_P]).
prime_decomposition(N, Z) :-
N #> 0,
indomain(N),
prime_decomposition_ceiled_square_root(N,SN),
prime_decomposition_1(N, SN, 2, [], Z).
prime_decomposition_1(1, _, _, L, L) :- !.
prime_decomposition_1(N, SN, D, L, LF) :-
(
0 #= N mod D ->
Q #= N // D,
prime_decomposition_ceiled_square_root(Q,SQ),
prime_decomposition_1(Q, SQ, D, [D |L], LF)
;
D1 #= D+1,
(
D1 #> SN ->
LF = [N |L]
;
prime_decomposition_2(N, SN, D1, L, LF)
)
).
prime_decomposition_2(1, _, _, L, L) :- !.
prime_decomposition_2(N, SN, D, L, LF) :-
(
0 #= N mod D ->
Q #= N // D,
prime_decomposition_ceiled_square_root(Q,SQ),
prime_decomposition_2(Q, SQ, D, [D |L], LF);
D1 #= D+2,
(
D1 #> SN ->
LF = [N |L]
;
prime_decomposition_2(N, SN, D1, L, LF)
)
).
prime_decomposition_ceiled_square_root(0, 0).
prime_decomposition_ceiled_square_root(N0, Root) :-
N1 #= N0 - 1,
Max in 0..N1,
R0^2 #= Max,
Root #= Root0 + 1,
fd_sup(R0, Root0).