ひとりで勝手にはじめた蟻本読書会 平面走査 計算幾何 蟻本読書会 の続きです。

凸包とグラハムスキャン

Beauty Contest (POJ No.2187)

二次元平面に N 箇所の牧場があります。i 番目の牧場は(x_i, y_i)にあります。同じ座標に複数の座標は存在しません。もっとも遠いところにある牧場の距離を求めよ。ただしNの最大値は50000とする。

このような問題を解く場合、N箇所の牧場の距離 N *(N – 1)/ 2 とおりすべてを調べていては制限時間内に間に合わせることはできません。省略できる計算を省略するにはどうすればよいかを考えます。

凸包上の点だけ調べる

ある3点を結んでできる三角形の内部にある点は最遠点対をなすことはありません。そこでこのような点を取り除く処理を繰り返していくと、与えられた点集合のうちもっとも外側にある点だけが残ります。このようなもっとも外側の点集合は、元の点集合を含む最小の凸多角形の頂点となり、この多角形を元の点集合の凸包といいます。凸包がわかればあとは凸包上のすべてのペアについてだけ距離を計算すればよいので、制限時間内に解を得ることができます。

凸包を求める方法

では凸包を得るにはどうすればよいのでしょうか?ここではグラハムスキャンを用いて凸包を求めます。まず点をX軸でソートします。ソート後の最初の点と最後の点はかならず凸包の頂点となります。あとは間の点をうえがわとしたがわにわけてそれぞれ求めます。

ソートされた点を繋げて凸包をつくっていきますが、点を追加することで凸ではない形になる場合があります。この場合は凹の部分を取り除いて処理を進めていきます。

上側であれば最初のふたつの点はリストに追加して、3つ目以降は最後と最後から二番目に追加された点で構成される線分の傾きと最後に追加された点とこれから追加されようとする点で構成される線分の傾きを比較します。後者のほうが大きいと凹の部分ができてしまうので、最後に追加された点を取り除き、もう一度同じような比較の処理をおこないます。これで凸包の上側を完成させることができます。

下側も同じような処理をおこない、両者を合わせれば凸包が完成します。

応用問題

D – Big Bang

D – Big Bang

天文学者である高橋君はその宇宙の膨張の速度を計測することにしました。

高橋君はある 2 つの日について、同じ N 個の星の位置を観測しました。星の位置は座標平面上の点として記録されます。つまり各日の観測結果は座標平面上の N 個の点からなる点集合になります。

2 回の観測の結果を見比べてみると、1 回目の観測結果である点集合に対して以下の 3 つの操作を順に実行すると 2 回目の観測結果である点集合に一致することがわかりました。

同じ向きに同じ距離だけ平行移動する。
原点を中心に同じ角度だけ回転する。
原点を中心に P 倍 (1 ≦ P) に相似拡大する。つまり点 (a, b) を点 (a×P, b×P) に移すという操作をすべての点に実行する。

P の値がわかれば膨張速度を求めることができそうです。1 回目と 2 回目の観測結果が与えられるので P を求めてください。

入力されるデータ
N
Ax_1 Ay_1
Ax_2 Ay_2
:
Ax_N Ay_N
Bx_1 By_1
Bx_2 By_2
:
Bx_N By_N

(ただし、
2 ≦ N ≦ 10^5
-15,000 ≦ Ax_i, Ay_i ≦ 15,000
-10^9 ≦ Bx_i, By_i ≦ 10^9

1 回目も 2 回目も、同じ点に複数の星が観測されることはない。
1 回目に観測された i 番目の星と 2 回目に観測された i 番目の星が同一の星とは限らない )

「1 回目に観測された i 番目の星と 2 回目に観測された i 番目の星が同一の星とは限らない」ので、AとBをそのまま比較することはできません。しかし「原点を中心に P 倍に相似拡大する」というのであれば1回目の観測でもっとも離れていた星のペアと2回目の観測でもっとも離れている星のペアは同じ星のペアであり、ここを比較すれば P の値を求めることができます。

動的凸包

C – 泥棒

C – 泥棒

あなたは、川と緑に囲まれた小さいながらも豊かな王国の泥棒です。
新しい王が治安向上のために監視所を設置し始めたので監視に引っかからないように気をつける必要があります。
監視所では他の監視所との間をまっすぐ結んだ線の上に誰がいるかを調べています。
あなたはこの線を横切ったり、線上の家に盗みに入ることはできません。
もちろん、監視所を通過することも出来ません
盗みに入る家と監視所の位置が与えられるので監視に引っかからずにアジトから盗みに入る家までたどり着けるかを判定し、監視に引っかからないなら SAFE 、引っかかるなら DANGER と出力せよ。

ただし、盗みに入る段階でまだ設置されていない監視所について監視に引っかかることはありません。

入力されるデータ
N
S_1 X_1 Y_1
S_2 X_2 Y_2

S_N X_N Y_N

ただし、N は盗みに入る家と監視所の数の合計を表す整数 (2 ≦ N ≦ 100,000)である。
S_i は TARGET もしくは MONITOR であり、それぞれ盗みに入る家と監視所を表している。
盗みに入る家・監視所は X_i, Y_i(1 ≦ X_i, Y_i ≦ 100,000,000)であり、すべて異なる位置にある。
家に盗みに入る日時・監視所が設置される日時は入力で与えられる順の通りである。
すなわち、ある家に盗みに入る時に既に設置されている監視所とはそれより前の入力で与えられた監視所のことである。
アジトは原点(0, 0)にある。

アジトが原点にあり、盗みに入る家と監視所の座標の最小値が 1 であることから、盗みに入る家が監視所によって囲まれていたら DANGER ということになります。この問題も凸包を使えば解けそうです。

前問では最初にすべての座標が与えられていましたが、この問題では凸包を動的に構成していくことになります。上半分と下半分にわけて凸包を構築します。X座標をみてそれぞれのどの位置に追加するのかを決めます。N ≦ 100,000 と大きいので、追加する位置は二分探索法で求めます。

すでに構築されている凸包の内部には点を追加しません。また点を追加するまえに凹んだ部分ができるかどうかを確認し、凹みができる場合はそのような点を取り除いてから追加の処理をおこないます。あとは同じです。

なお、凸包の内部に相当するか?点を追加して凹んだ部分ができるかどうかは符号付き面積を利用して判定しています。