AGC021 - B - Holes
問題文
atcoder.jp十分大きい円(半径 )の中に穴が 個あって、穴 , 穴 , 穴 まである。
確率的に一様にどこかの座標にすぬけ君を置く。
その時すぬけ君はユークリッド距離で一番近い穴に入る。
このとき、全ての において 穴 に入る確率を求めよ
解法
まず 点について考えると、垂直二等分線を引けば、近い側が明らかになる。
が十分大きいので、は原点に垂直二等分線を引いたのと近似できる。
そのため、答えはどちらも になる。
次に、いくつかの穴があった時の ある穴のある点 について着目してみる。
他の穴の側に行かなければいいので、他の穴についての垂直二等分線を見て、 側である方の範囲を AND すれば(積集合を求めれば?)、範囲が分かることになる。
もし、 点 を完全に囲うような形で、垂直二等分線を引かれていた場合、その面積は に依存しない定数になるため、 が十分大きいので 答えが になる。
このような条件は 点 がこの点集合の凸包に含まれていないことが同値である。
凸包に含まれていない点の答えが になるとわかった。
では、凸包に含まれている点はどうなっているだろうか。
さっきと同じ理論で、垂直二等分線を任意の位置に移動しても答えがほとんど変わらないので全て 点 に移動するものと考えてみる。
すると、実は関係しているものは 凸包において点 に隣り合っている点に対する線のみであるということが分かる。
凸包において隣り合っている点をそれぞれ 点 と置いてみる。
と置いてみると、
求めたい角度は であることが分かる。(凸性があるので である、よって )。
答えは確率であるため、 答えは となる。
の見つけ方は色々とあると思う。
今回の問題では実は凸包の専門的なアルゴリズム(Andrew Scanみたいな)を使わなくても解けて、
点 からの任意の点の角度をソートした時に 差が を超えた点 があるなら、 は凸包の点で は と隣り合っている。
の中に全部角度が収まっていることになるからである。
そしてその角度は より小さいので は凸包の点である。
Source
V2は 次元ベクトルのデータ構造ですvoid Main() { int N; cin >> N; vector<V2> points(N); for (auto &p : points) cin >> p.x >> p.y; vdouble ans(N, 0); for (int i = 0; i < N; i++) { vdouble angles; for (int j = 0; j < N; j++) { if (i==j) continue; V2 vec = points[j]-points[i]; angles.push_back(atan2(vec.y, vec.x)); } sort(begin(angles), end(angles)); angles.push_back(angles[0]+2*M_PI); for (int j = 0; j < angles.size(); j++) { int k = j+1; if (k >= angles.size()) k -= angles.size(); if (angles[k]-angles[j] > M_PI + EPS) { ans[i] = angles[k]-angles[j]-M_PI; } } cout << ans[i] / 2 / M_PI << el; } }