TopCoder SRM 503 Div1 Medium: KingdomXCitiesandVillages
解法
村vについて考える。
- 村vが最初に選ばれる確率は1/M
- 村vからj番目に近い村wに道路を敷く時、
- 村wは接続済みでなければならない
- 村wよりも村vに近い村は接続されていてはならない
- それ以外の村が接続されているかどうかは答に影響しないので、「それ以外の村がk個接続されている時」というようにまとめてkを変化させれば良い。
解法
import java.util.ArrayList; import java.util.Collections; public class KingdomXCitiesandVillages { public double determineLength(int[] cX, int[] cY, int[] vX, int[] vY) { int N = cX.length; int M = vX.length; double ans = 0; for (int v = 0; v < M; v++) { // 村vから道を敷く場合を考える // 街への最短距離 double cityDist = 1e9; for (int j = 0; j < N; j++) { cityDist = Math.min(cityDist, dist(vX[v], vY[v], cX[j], cY[j])); } // 自身以外の村への距離 ArrayList<Double> villageDist = new ArrayList<>(); for (int v2 = 0; v2 < M; v2++) { if (v2 != v) { villageDist.add(dist(vX[v], vY[v], vX[v2], vY[v2])); } } Collections.sort(villageDist); // 村vが最初に選ばれる ans += cityDist / M; for (int j = 0; j < M - 1; j++) { // 村vからj番目(0-indexed)に近い村が選ばれる時、少なくともj個の村は街と接続されていない int otherVillages = M - 1 - j; double dist = Math.min(villageDist.get(j), cityDist); for (int k = 1; k <= otherVillages; k++) { // 村vが接続される前に、 確実に接続されていないj個の村以外の村のうち、k個の村が接続されているとする。 // j番目の村を除くotherVillages-1のうちk-1個が選ばれる組み合わせの数 double combi1 = mCn(otherVillages - 1, k - 1); // 全ての街からk個を選ぶ組み合わせ double combi2 = mCn(M, k); ans += dist * combi1 / combi2 / (M - k); } } } return ans; } private double mCn(int m, int n) { // 愚直にやっても大した量にならない double combi = 1.0; for (int i = 0; i < n; i++) { combi *= (m - i); combi /= (i + 1); } return combi; } private double dist(int x1, int y1, int x2, int y2) { long dx = x1 - x2; long dy = y1 - y2; return Math.sqrt(dx * dx + dy * dy); } }