Euler: Problem 91

Posted by YpsilonTAKAI On 2013年2月1日金曜日 0 コメント

格子点を使って直角三角形を作る問題です。

まずは、格子から2点を取って、原点合せた3点でできる三角形が直角を含むかどうかをチェックしてみたのですが、10分という想像以上の時間がかかってしまい、別解を考えました。
このとき、「直交するベクトルの内積は0になる」なんていうのを使ったのですが、かなり懐かしい感じでした。




三角形の種別を直角の場所によって3つに分けます。
1. 直角が原点にあるもの。
2. 直角が、x軸またはy軸上にあるもの。
3. 直角が、上記の点以外にあるもの。

1と2にあてはまる三角形の数は簡単です。
1であれば、原点以外の2点がx軸とy軸にあればいいので、50*50=250個。
2の場合、一点がx軸上にあれば、のこりの点は、その上の格子点にあるので、50個。x軸上の点は50こあるので、50*50=250個。 y軸上でも同じ数だけあります。
ということで、1と2で、250*3で、750個あることになります。

さて、3です。
ある点P(p,q)を取ると、求める残りの点はPを通り、OPと垂直な線上にあります。その線の方程式を作って、そのグラフの通る格子点を求めれば、Pを含んで、角Pが直角の三角形がすべて求められるということになります。

Pを通る直線の方程式は、y=a(x-p)+q (aは傾き)です。
OPの傾きはq/pなので、それと垂直な線の傾きは、-p/qになります。
gradient-1が垂直な線の傾きを求める関数で、third-pointが与えた点を通る直交する線の関数を返す関数になっています。


;; problem 90
;;"Elapsed time: 1096.673113 msecs"
(require '[clojure.test :as test])
(require '[clojure.math.combinatorics :as combo])
(defn points [size]
(let [matrix-size size
points (for [x (range (inc matrix-size))
y (range (inc matrix-size))
:when (not= 0 x y)]
[x y])]
points))
(defn gradient-1
([point] (gradient-1 [0 0] point))
([[x1 y1] [x2 y2]] (- (/ (- x2 x1) (- y2 y1)))))
(defn third-point [[p q :as point]]
(fn [x] [x
(+ (* (gradient-1 point) (- x p))
q)]))
(defn find-all-orthogonal-line [point max-val]
(->> (map (third-point point) (range (inc max-val)))
(filter #(not= point %) ,,)
(filter #(every? integer? %) ,,)
(filter (fn [[x y]] (<= 0 y max-val)) ,,)
(map #(vector point %) ,,)))
(defn pe-91 [mat-size]
(+ (* 3 (* mat-size mat-size))
(->> (points mat-size)
(filter #(every? (complement zero?) %) ,,)
(mapcat #(find-all-orthogonal-line % mat-size) ,,)
(count ,,))))
view raw pe_91.clj hosted with ❤ by GitHub
;; problem 90
(require '[clojure.test :as test])
(require '[clojure.math.combinatorics :as combo])
(defn vectorize [l]
(let [[[x1 y1] [x2 y2]] l]
[(- x2 x1) (- y2 y1)]))
(test/is (= (vectorize [[3 1] [5 4]])
[2 3]))
(defn right-angle? [l1 l2]
(let [[x1 y1] (vectorize l1)
[x2 y2] (vectorize l2)]
(= (+ (* x1 x2) (* y1 y2))
0)))
(test/is (= (right-angle? [[3 1] [5 4]] [[0 0] [-3 2]])
true))
(defn point-pairs [size]
(let [matrix-size size
points (for [x (range (inc matrix-size))
y (range (inc matrix-size))
:when (not= 0 x y)]
[x y])
selections (combo/combinations (range (count points)) 2)]
(for [[a b] selections]
[(nth points a) (nth points b)])))
(defn has-right-angle? [[point-a point-b]]
(let [line-a [[0 0] point-a]
line-b [[0 0] point-b]
line-c [point-a point-b]]
(or (right-angle? line-a line-b)
(right-angle? line-a line-c)
(right-angle? line-b line-c))))
(->> (point-pairs 50)
(filter has-right-angle? ,,)
(count ,,))
;;"Elapsed time: 629846.902845 msecs"
;; tooooo slow!
view raw pe_91_slow.clj hosted with ❤ by GitHub

0 コメント:

コメントを投稿