多测,$T \leq 100, M \leq 100, N \leq 100$
给出 $M$ 个 $N$ 维空间中的点,满足两两之间距离为 1。
最多能再加入多少个点,使得仍然满足两两之间距离为 1,输出方案。
解决第一个问题,考虑归纳一下,在一维的时候,可以是一个直线,然后每加一维都可以多一个点。所以答案是 $M-N+1$。
然后考虑目前有 $C$ 个点,随机出来一个 $N$ 维点和这 $C$ 个点很大概率线性无关。所以我们可以容易的找到这个点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| using ar = valarray<double>; double dot(const ar &x, const ar &y) { double res = 0; rep(i, sz(x)) res += 1. * x[i] * y[i]; return res; } const double eps = 1e-9; void solve() { int n, m; cin >> n >> m; vc<ar> v(m, ar(n)); rep(i, m) for (auto &d : v[i]) { string s; cin >> s; d = stod(s); } uniform_real_distribution<double> rnd(-10, 10); rep(i, m, n + 1) { ar o(n); for (auto vv : v) o += vv; o /= i; auto vv = v; for (auto &vvv : vv) vvv -= o; rep(k, i) rep(j, k) { auto x = (vv[j]) * dot(vv[k], vv[j]); vv[k] -= x; if (dot(vv[k], vv[k]) < eps) continue; auto t = dot(vv[k], vv[k]); vv[k] /= sqrt(t); } ar d(n); for (auto &dd : d) dd = rnd(rng); rep(j, i) { auto x = (vv[j]) * dot(d, vv[j]); d -= x; double t = dot(d, d); d /= sqrt(t); } double l = sqrt(1. - dot(v[0] - o, v[0] - o)); v.pb(o + d * l); } static int cas = 0; cout << "Case #" << ++cas << ": " << n + 1 - m << "\n"; cout << fixed << setprecision(10); rep(i, m, n + 1) { for (int j = 0; j < n; j++) cout << v[i][j] << " \n"[j + 1 == n]; } rep(i,n+1){ rep(j,n+1){ if(i==j)continue; if(abs(dot(v[i]-v[j],v[i]-v[j])-1)>eps){ debug(i,j,dot(v[i]-v[j],v[i]-v[j])); } } } }
|