Last active
December 10, 2015 13:49
-
-
Save plaster/4443424 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;;; Project Euler Problem 23 solution | |
;;; http://projecteuler.net/problem=23 | |
(use 'clojure.test) | |
(def limit 28123) | |
(defn gen-sigma1-list | |
"original implementation by @ypsilon-takai: https://gist.github.com/4284814" | |
[^long size] | |
(loop [i 2 | |
a (long-array size)] | |
(if (< (* 2 i) size) | |
(recur (inc i) | |
(loop [j (* 2 i) | |
a a] | |
(if (< j size) | |
(recur (+ j i) | |
(do (aset a j (+ (aget a j) i)) | |
a)) | |
a))) | |
a))) | |
(defn gen-divisors [n] (filter #(zero? (mod n %)) (range 1 n))) | |
(defn abundant? [n] (< n (apply + (gen-divisors n)))) | |
(defn gen-abundants [size] | |
(let [sigma1-list (gen-sigma1-list size)] | |
(filter #(< % (aget sigma1-list %)) | |
(range 1 size)))) | |
(is (not-any? abundant? (range 1 12))) | |
(is (abundant? 12)) | |
(defn gen-sums | |
"candidates-ascending 中の2要素のすべての組み合わせについて和を計算する(thanks to @kohyama)" | |
[candidates-ascending] | |
(for [x candidates-ascending | |
y candidates-ascending | |
:while (<= y x) | |
:let [sum (+ x y)] | |
:while (<= sum limit) | |
] | |
sum)) | |
;; 補集合X-Aの要素の総和は、全体集合Xの要素の総和から部分集合Aの要素の総和を引いたものに等しい | |
;; thanks to @tnoda | |
(defn solve [] | |
(let [abundants (filter abundant? (range 12 (inc limit))) | |
abundant-sums (set (gen-sums abundants))] | |
(- (apply + (range (inc limit))) | |
(apply + abundant-sums)))) | |
(defn solve2 [] | |
(let [abundants (gen-abundants (inc limit)) | |
abundant-sums (set (gen-sums abundants))] | |
(- (apply + (range (inc limit))) | |
(apply + abundant-sums)))) | |
;; (is (= (solve) 4179871)) | |
;pe-23.core=> (time (solve)) | |
;"Elapsed time: 25569.034676 msecs" | |
;4179871 | |
;pe-23.core=> (time (solve2)) | |
;"Elapsed time: 1789.932635 msecs" | |
;4179871 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;;; Project Euler Problem 23 solution | |
;;; http://projecteuler.net/problem=23 | |
(use 'clojure.test) | |
(def limit 28123) | |
(defn gen-divisors [n] (filter #(zero? (mod n %)) (range 1 n))) | |
(defn abundant? [n] (< n (apply + (gen-divisors n)))) | |
(is (not-any? abundant? (range 1 12))) | |
(is (abundant? 12)) | |
(defn gen-sums | |
"candidates-ascending 中の2要素のすべての組み合わせについて和を計算する" | |
[candidates-ascending] | |
(if (empty? candidates-ascending) | |
nil | |
(let [ [lhs & larger-candidates] candidates-ascending ] | |
(concat | |
(for [rhs candidates-ascending | |
:let [sum (+ lhs rhs)] | |
:while (<= sum limit) | |
] | |
sum) | |
(lazy-seq (gen-sums larger-candidates)))))) | |
(defn solve [] | |
(let [abundants (filter abundant? (range 12 (inc limit))) | |
abundant-sums (set (gen-sums abundants))] | |
(apply + (remove #(contains? abundant-sums %) | |
(range 1 (inc limit)))))) | |
;; (is (= (solve) 4179871)) |
@tnodaさん
ただ,今回に限っては,
(- (apply + (range (inc limit)) (apply + abundant-sums))のほうが速かったかもしれません.
なるほど!補集合を求めてから総和を計算するのと、総和をそれぞれ計算して差を取るの、まったく等価ですね。
この性質は見落としてました。コードもシンプルになりますし、素晴らしいとおもいます。反映します。
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@kohyamaさんの提示のfor文の変数束縛の方法ですが、僕もこれが使えるのを知るまでは、whileで書いてました。
変数は順番に束縛されるのでこういつ使いかたができるんですね。
以前の自分の回答を見てみると、結果を出すのに2時間もかかっているらしい。 リベンジしないといけませんね。