#include #include #include #include #include using namespace std; typedef complex V2; const double EPS = 1e-6; double square(double x) { return x * x; } double to_nonzero(double x) { return abs(x) >= EPS ? x : (x > 0 ? 1 : -1) * EPS; } struct Function { const int N; vector > distance; vector > nontrivial_pairs; Function(const vector &c) : N(c.size()) { distance = vector >(N, vector(N)); for (int i = 0; i < N; i++) for (int j = i+1; j < N; j++) distance[i][j] = distance[j][i] = abs(c[i] - c[j]); vector r_max(N, 9999); for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) if (j != i && abs(j-i) != 1 && abs(j-i) != N-1) r_max[i] = min(r_max[i], distance[i][j]); for (int i = 0; i < N; i++) { for (int j = i+1; j < N; j++) { bool should_intersect = (j-i == 1 || j-i == N-1); if (should_intersect || r_max[i] + r_max[j] > distance[i][j]) nontrivial_pairs.push_back(make_pair(i, j)); } } } double get_pair_deviation(const valarray &r, const pair &p) const { int i = p.first; int j = p.second; bool should_intersect = (j-i == 1 || j-i == N-1); double d = r[i] + r[j] - distance[i][j]; if ((should_intersect && d < 0) || (!should_intersect && d > 0)) return d; return 0; } double evaluate(const valarray &r) const { double error = 0; for (int k = 0; k < nontrivial_pairs.size(); k++) error += square(get_pair_deviation(r, nontrivial_pairs[k])); for (int i = 0; i < N; i++) if (r[i] < 0) error += square(r[i]); else if (r[i] > 10000) error += square(r[i] - 10000); return error; } valarray get_gradient(const valarray &r) const { valarray g(0.0, N); for (int k = 0; k < nontrivial_pairs.size(); k++) { double deviation = get_pair_deviation(r, nontrivial_pairs[k]); g[nontrivial_pairs[k].first ] += 2 * deviation; g[nontrivial_pairs[k].second] += 2 * deviation; } for (int i = 0; i < N; i++) if (r[i] < 0) g[i] += r[i]; else if (r[i] > 10000) g[i] += r[i] - 10000; return g; } }; // 黄金分割法 valarray minimize_along_line(const Function &f, const valarray &x, const valarray &dx) { static const double K = 0.381966011250105; // 2 / (3 + sqrt(5)) double a = 0, b = 1, t = K * (b - a), c = a + t, d = b - t; double fc = f.evaluate(x + dx * c); double fd = f.evaluate(x + dx * d); while (d - c > EPS) if (fc > fd) { a = c; c = d; fc = fd; d = b - K * (b - a); fd = f.evaluate(x + dx * d); } else { b = d; d = c; fd = fc; c = a + K * (b - a); fc = f.evaluate(x + dx * c); } return x + dx * c; } // 準ニュートン法 (Broyden-Fletcher-Goldfarb-Shanno 法) void minimize(const Function &f, valarray &x) { const int N = x.size(); valarray > hi(valarray(0.0, N), N); for (int i = 0; i < N; i++) hi[i][i] = 1; double fx = f.evaluate(x); valarray g = f.get_gradient(x); valarray dx = -g; for (int loop = 0; loop < 8 * N; loop++) { static const double TOLERANCE = 3e-8; double fx0 = fx; x = minimize_along_line(f, x, dx); fx = f.evaluate(x); if (2 * abs(fx - fx0) <= TOLERANCE * (abs(fx) + abs(fx0) + EPS)) break; valarray dg(g); g = f.get_gradient(x); dg = g - dg; valarray hi_dg(N); for (int i = 0; i < N; i++) hi_dg[i] = (hi[i] * dg).sum(); double dx_dg = to_nonzero((dx * dg).sum()); double dg_hi_dg = to_nonzero((dg * hi_dg).sum()); double dx_dg_inv = 1 / dx_dg; double dg_hi_dg_inv = 1 / dg_hi_dg; valarray u = dx * dx_dg_inv - hi_dg * dg_hi_dg_inv; for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) hi[i][j] += dx[i]*dx[j]*dx_dg_inv - hi_dg[i]*hi_dg[j]*dg_hi_dg_inv + u[i]*u[j]*dg_hi_dg; for (int i = 0; i < N; i++) dx[i] = -((hi[i] * g).sum()); } } int main() { for (int N; cin >> N, N; ) { vector c(N); for (int i = 0; i < N; i++) { double x, y; cin >> x >> y; c[i] = V2(x, y); } static bool first = true; if (first) first = false; else printf("\n"); Function f(c); valarray r(0.0, c.size()); minimize(f, r); for (int i = 0; i < N; i++) printf("%.6f\n", max(r[i], 0.0)); // -0.000000 とか防止 } return 0; }