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)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@tnodaさん
なるほど!補集合を求めてから総和を計算するのと、総和をそれぞれ計算して差を取るの、まったく等価ですね。
この性質は見落としてました。コードもシンプルになりますし、素晴らしいとおもいます。反映します。