用Prolog / clpfd解决项目Euler#303

时间:2015-12-06 19:45:48

标签: prolog clpfd

此处出现Project Euler Problem 303,“带小数字的倍数”。

  

对于正整数n,将f(n)定义为n的最小正数,用基数10表示,仅使用数字≤2。

     

因此f(2)= 2,f(3)= 12,f(7)= 21,f(42)= 210,f(89)= 1121222。

     

另外,p303_formula100

     

查找p303_formula10000

这是我已编写/我想改进的代码:

:- use_module(library(clpfd)).

n_fn(N,FN) :- 
   F  #> 0,
   FN #= F*N,
   length(Ds, _),
   digits_number(Ds, FN),
   Ds ins 0..2,
   labeling([min(FN)], Ds).

该代码已经可用于解决少量小问题实例:

?- n_fn(2,X).
X = 2

?- n_fn(3,X).
X = 12 

?- n_fn(7,X).
X = 21 

?- n_fn(42,X).
X = 210 

?- n_fn(89,X).
X = 1121222 

我可以做些什么来解决上述挑战“发现:总和(n = 1到10000)(f(n)/ n)”

如何在合理的时间内解决更多更大的实例?

请与我分享您的想法!提前谢谢!

2 个答案:

答案 0 :(得分:2)

9点慢,有一个模式.. 所以..

n_fn(9,12222):-!.
n_fn(99,1122222222):-!.
n_fn(999,111222222222222):-!.
n_fn(9999,11112222222222222222):-!.

但我相信让prolog找到这个模板并调整搜索会更好..不知道你会怎么做!

一般来说,它必须重新计算很多结果。

答案 1 :(得分:2)

我无法发现此问题的重现关系。所以,最初我认为记忆可以加快速度。不是......

此代码基于clp(fd),比你的......

略快
n_fn_d(N,FN) :- 
        F  #> 0,
        FN #= F*N,
        digits_number_d([D|Ds], Ts),
        D in 1..2,
        Ds ins 0..2,
        scalar_product(Ts, [D|Ds], #=, FN),
        labeling([min(FN)], [D|Ds]).

digits_number_d([_], [1]).
digits_number_d([_|Ds], [T,H|Ts]) :-
        digits_number_d(Ds, [H|Ts]), T #= H*10.

当我使用clp(fd)来解决Eu​​ler的问题时,我偶然发现性能不佳......有时候,简单的“生成和测试”与本机算法结合起来会产生影响。

这个更简单,'原生'基于:

n_fn_e(N,FN) :- 
    digits_e(FN),
    0 =:= FN mod N.

digits_e(N) :-
    length([X|Xs], _),
    maplist(code_e, [X|Xs]), X \= 0'0,
    number_codes(N, [X|Xs]).
code_e(0'0).
code_e(0'1).
code_e(0'2).

它的速度更快:

test(N) :-
    time(n_fn(N,A)),
    time(n_fn_d(N,B)),
    time(n_fn_e(N,C)),
    writeln([A,B,C]).

?- test(999).
% 473,671,146 inferences, 175.006 CPU in 182.242 seconds (96% CPU, 2706593 Lips)
% 473,405,175 inferences, 173.842 CPU in 178.071 seconds (98% CPU, 2723188 Lips)
% 58,724,230 inferences, 25.749 CPU in 26.039 seconds (99% CPU, 2280636 Lips)
[111222222222222,111222222222222,111222222222222]
true