プロジェクトオイラー問92

http://odz.sakura.ne.jp/projecteuler/index.php?cmd=read&page=Problem%2092
Problem 92 「桁の2乗による連鎖」 †
どんな数から初めても桁の2乗和は89か1になる。
1000万以下の89になる数が何個あるか答えよ。

10を0000010のように解釈すれば。
全ての数を7ケタで考えることができます。
桁の2乗和は並べ替えても結果が同じなので、0012738や0102378などは0012378で代表して計算がすみます。
後は代表だけを全探索するだけです。
これで計算時間0.2秒です。
C++なら配列によるメモ化が使えるのでもっと早くなります。


seed([_,_,_,_,_,_,_]).

perm([],N):-N>0,!.
perm([],_):-!,fail.
perm([X|Xs],N):-
	between(N,9,X),
	perm(Xs,X).

keta2Wa([],Sum,Sum):-!.
keta2Wa([X|Xs],Sum,Result):-
	Sum1 is Sum+X^2, 
	keta2Wa(Xs,Sum1,Result).

keta2WaA(0,Sum,Sum):-!.
keta2WaA(N,Sum,Result):-
	N1 is N//10,
	Sum1 is Sum+(N mod 10)^2,
	keta2WaA(N1,Sum1,Result).

fact(N,D):-nth0(N,[1,1,2,6,24,120,720,5040,40320],D).

divs([],C,Div,Result):-
	!, 
	fact(C,Div1),
	Result is Div*Div1.
divs([X,X|Xs],C,Div,Result):-
	!,
	C1 is C+1,
	divs([X|Xs],C1,Div,Result).
divs([_|Xs],C,Div,Result):-
	!,
	fact(C,Div1),
	Div2 is Div*Div1,
	divs(Xs,1,Div2,Result).

calc(1):-!,fail.
calc(89):-!.
calc(N):-
	keta2WaA(N,0,N1),
	calc(N1).

sum([],Sum,Sum):-!.
sum([X|Xs],Sum,Result):-
	Sum1 is Sum+X,
	sum(Xs,Sum1,Result).

 search(E):-
	seed(X),
	perm(X,0),
 	divs(X,1,1,D),
	E is 5040//D,
	keta2Wa(X,0,Num),
	calc(Num).

main:-
	findall(E,search(E),Es),
	sum(Es,0,Ans),
	write(Ans).
最終更新:2014年12月19日 10:10