点の偏角とは、原点からその点を見たときの方向を角度として表したものです。与えられたいくつかの点を偏角の昇順に並べ替える操作を偏角ソートといいます。

E – Laser Takahashi

E – Laser Takahashi

点Aと点Bに挟まれる点の数を求めよという問題です。

偏角と偏角ソート

この問題では偏角ソートをすることで赤い点で挟まれている点を効率よく数えることができます。

偏角を求めるにはMath.Atan2メソッドを使えばできそうですが、小数による誤差が発生するかもしれません。そこで別の方法を使います。

ソートの比較関数を外積を用いて定義します。ただし、注意点があります。この方法は偏角の差が 180度 未満の時にしか用いることができません。そこで点を上半平面(y > 0 または (y == 0 かつ x > 0))と下半平面(それ以外)にわけます。これで偏角が[0, 180)と[180, 360)のグループにわかれるので、あとはこのなかでソートすればよいです。

同じ偏角を持つ点が複数ある場合の対処法

偏角ソートしたら点Aの偏角から点Bの偏角で挟まれている点の数を数えればよいのですが、点A, Bと同じ偏角を持つ点が複数あるかもしれないのでそれらを見つける必要があります。

ソートされた点であれば、偏角が同じものがあるとすればその前後です。そこで偏角が同じかどうかを判定するメソッドを定義します。

外積が同じなら2点は同一直線です。ただしこれだけだと原点を挟んでいる(180度ズレている)かもしれないので上下どちらの半平面に属するかも確認します。

あとは前から順に見ていってIsSameDeclinationがtrueを返したら同じグループにしてしまえばOKです。

提出コード

実際に提出してAC(正解)したコードです。

009 – Three Point Angle(★6)

ある方から課題をいただいているのでこれも片付けておきます。

009 – Three Point Angle(★6)

3つの点を選んでできる角の角度の最大値を度数法で出力せよという問題です。相対誤差または絶対誤差が 10^-7 なら正解として扱われます。

これも偏角ソートすればなんとかなりそうです。また角度は誤差がある程度は許容されるのでMath.Atan2を使って問題なさそうです。

3点からできる角は中心とその他の2つにわけて考える

3点からできる角は中心とその他の2つにわけて考えるとうまくいく場合が多いです。

まず中心になる点を選びます。この点が原点になるように全体を平行移動させます。中心になる点を O、残りの2点を A, B、X軸にあるX座標が正になる任意の点を C とすると ∠AOC – ∠BOC が180度に近くなるものを探せばよいことになります。

まず中心の点以外のすべての点の偏角を求めます。それぞれに対してこれに180度を足したものが一番近い別の偏角を探します。このとき二分探索法が使えます。

ある点の偏角に180度を足したものが一番近い別の偏角を探すのに二分探索法を使うと時間計算量は O(logN)、これをすべての点についておこなうので O(NlogN)、中心になる点は全部でNとおりあるのでこれをN回おこなうことになるので全体の時間計算量は O(N×N×logN)となります。N は最大2,000なのでこれなら充分間に合います。