Problem Specification Value
Time Limit 1 Sec
Memory Limit 162 MB
Submit 4156
Solved 2183

Description

有一个球形空间产生器能够在 n 维空间中产生一个坚硬的球体. 现在, 你被困在了这个 n 维球体中, 你只知道球面上 n+1 个点的坐标, 你需要以最快的速度确定这个 n 维球体的球心坐标, 以便于摧毁这个球形空间产生器.

Input

第一行是一个整数 n (1<=N=10). 接下来的 n+1 行, 每行有 n 个实数, 表示球面上一点的 n 维坐标. 每一个实数精确到小数点后 6 位, 且其绝对值都不超过 20000.

Output

有且只有一行, 依次给出球心的 n 维坐标 (n 个实数), 两个实数之间用一个空格隔开. 每个实数精确到小数点后 3 位. 数据保证有解. 你的答案必须和标准输出一模一样才能够得分.

Sample Input

2
0.0 0.0
-1.0 1.0
1.0 0.0

Sample Output

0.500 1.500

HINT

提示: 给出两个定义: 1、球心: 到球面上任意一点距离都相等的点. 2、距离: 设两个 n 为空间上的点 A, B 的坐标为 (a1, a2,. ...... , an), (b1, b2,. ...... , bn), 则 AB 的距离定义为: dist=sqrt ((a1-b1) ^2+(a2-b2) ^2+...... +(an-bn) ^2)

Source


花了很大功夫写了两个版本, 一个是让人写到吐的模拟退火, 另一个是相对友善的高斯消元法. 模拟 退火调了很久很久但是还有许多 BUG, 不过最后还是用高斯消元法 AC 了.



#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>

using namespace std;
typedef long double lf;
#define sqr(____x) ((____x) * (____x))
const int maxn = 20;

int n;
lf  coords[maxn][maxn]; // Actual coordinates
lf  mat[maxn][maxn]; // The matrix of linear equations
lf  res[maxn]; // The actual results

int main(int argc, char** argv)
{
    // Read-in data
    scanf("%d", &n);
    for (int i = 0; i <= n; i++)
        for (int j = 1; j <= n; j++)
            scanf("%Lf", &coords[i][j]);
    // Pre-process coords to create matrix
    // 2x(a_2-a_1) + 2y(b_2-b_1)=a_1^2+b_1^2-a_2^2-b_2^2
    for (int i = 1; i <= n; i++) { // Iterate through a_1, 2, 3...
        for (int j = 1; j <= n; j++) // Iterate through x, y, z...
            mat[i][j] = 2.0 * (coords[i][j] - coords[i - 1][j]);
        // Calculate final coefficient
        mat[i][n + 1] = 0.0;
        for (int j = 1; j <= n; j++)
            mat[i][n + 1] += sqr(coords[i - 1][j]) - sqr(coords[i][j]);
    }
    // Calculate matrix using Gaussian Elimination
    // Convert matrix to echelon form
    for (int i = 1; i <= n - 1; i++) { // The equation to be examined
        // To ensure that there's no zero on this particular position
        if (mat[i][i] == 0) {
            // Search through the entire matrix in hope of finding one
            int found = 0;
            for (int j = 1; j <= n; j++)
                if (mat[j][i] != 0)
                    found = j;
            if (!found)
                continue; // We don't need this after all
            // Copying the specific row and add to this row
            for (int j = 1; j <= n + 1; j++)
                mat[i][j] += mat[found][j];
        }
        // Now to solve the elimination
        for (int j = i + 1; j <= n; j++) { // The equation to be eliminated
            lf  elim = - mat[j][i] / mat[i][i];
            for (int k = 1; k <= n + 1; k++)
                mat[j][k] += elim * mat[i][k]; // Eliminate row
            mat[j][i] = 0.0; // Ensure clearness
        }
    }
    // Process echelon matrix to get answers
    for (int i = n; i >= 1; i--) {
        // Take in known values
        for (int j = i + 1; j <= n; j++) {
            mat[i][n + 1] -= mat[i][j] * res[j];
            mat[i][j] = 0.0;
        }
        // Resize this value
        mat[i][n + 1] /= mat[i][i];
        mat[i][i] = 1.0;
        // Upload to final result table
        res[i] = mat[i][n + 1];
    }
    // Print values
    for (int i = 1; i < n; i++)
        printf("%.3Lf ", - res[i]);
    printf("%.3Lf\n", - res[n]); // Or you will get Presentation Error~ 233
    return 0;
}

这就是写吐了的模拟退火----不要借鉴这份代码, 如果它遇到 x-y 比例严重失调的图形会崩掉


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>

using namespace std;
typedef long double lf;
#define sqr(____x) ((____x) * (____x))
const int maxn = 20, maxm = 1010;

int n, spawns = 1, iterts = 32;
lf  xa[maxn][maxn]; // index, dimension
lf  mx_x[maxn], mn_x[maxn]; // dimension, representing extreme values
lf  spx[maxn][maxn]; // spawns: index, dimension
lf  spv[maxn]; // spawns: the current entropy
lf  mx_d, mn_d;
lf  delta, epsilon = 1.0e-6;

lf  calc_entropy(lf* arrx)
{
    lf  val[maxn], sum = 0.0;
    for (int i = 0; i <= n; i++) {
        val[i] = 0.0;
        for (int j = 1; j <= n; j++)
            val[i] += sqr(xa[i][j] - arrx[j]);
        sum += val[i];
    }
    sum /= (lf)(n + 1); // Now sum becomes average / mean
    for (int i = 0; i <= n; i++)
        val[i] = sqr(val[i] - sum);
    sum = 0.0;
    for (int i = 0; i <= n; i++)
        sum += val[i]; // The sum of it's squared distinction
    sum /= (lf)n; // The final result;
    return sum;
}

lf  myrand(lf range)
{
    return rand() * range * 2.0 / RAND_MAX - range;
}

lf  myrand(lf range_l, lf range_r)
{
    return rand() * (range_r - range_l) / RAND_MAX + range_l;
}

lf  center[maxn]; // Pre-processing for precision

int main()
{
    scanf("%d", &n);
    // Set extreme values
    for (int j = 1; j <= n; j++) {
        mx_x[j] = -40000.0;
        mn_x[j] = 40000.0;
    }
    mx_d = 0.0;
    mn_d = 80000.0;
    // Input known coordinates
    for (int i = 0; i <= n; i++)
        for (int j = 1; j <= n; j++) {
            scanf("%Lf", &xa[i][j]);
            mx_x[j] = max(mx_x[j], xa[i][j]);
            mn_x[j] = min(mn_x[j], xa[i][j]);
            center[j] += xa[i][j];
        }
    // Pre-processing graph
    for (int j = 1; j <= n; j++) {
        mx_d = max(mx_d, mx_x[j] - mn_x[j]);
        mn_d = min(mx_d, mx_x[j] - mn_x[j]);
        // Processing side-slipping
        center[j] /= (lf)(n + 1);
        for (int i = 0; i <= n; i++)
            xa[i][j] -= center[j];
        mx_x[j] -= center[j];
        mn_x[j] -= center[j];
    }
    if (mn_d < 1.0)
        epsilon *= mn_d; // .*
    else
        epsilon /= mn_d;
    for (int j = 1; j <= n; j++) {
        for (int i = 0; i <= n; i++)
            xa[i][j] /= mx_d;
        mx_x[j] /= mx_d;
        mn_x[j] /= mx_d;
    }
    // Defining initial precision
    delta = 20000.0;
    // Spawning the initial points
    for (int k = 1; k <= spawns; k++)
        for (int i = 1; i <= n; i++)
            spx[k][i] = myrand(mn_x[i], mx_x[i]);
    for (int k = 1; k <= spawns; k++)
        spv[k] = 8.9e10;
    // Simulated annealing
    while (delta > epsilon) {
        for (int k = 1; k <= spawns; k++) {
            lf  tstx[maxn]; // The sub-routines of this spawn
            lf  best = spv[k];
            // Iterating children on the tree
            for (int i = 1; i <= iterts; i++) {
                lf  nwx[maxn];
                // Generating new node
                for (int j = 1; j <= n; j++)
                    nwx[j] = spx[k][j] + myrand(delta);
                // calculating entropy
                lf  curval = calc_entropy(nwx);
                // cout << curval << endl;
                // If not even better than the original, forget it
                if (curval >= best) continue;
                // Then we'll copy it to the temporary storage
                for (int j = 1; j <= n; j++)
                    tstx[j] = nwx[j];
                best = curval;
            }
            // Done spawning, we shall look over whether to update this spawn
            if (best >= spv[k]) continue;
            // That was nothing happened, now it's getting better!
            for (int j = 1; j <= n; j++)
                spx[k][j] = tstx[j];
            spv[k] = best;
        }
        if (delta <= 100 || spv[1] > 10.0)
            delta *= 0.7071; // .*
    }
    // Generating average values
    lf  avr[maxn];
    for (int j = 1; j <= n; avr[j] = 0.0, j++);
    for (int i = 1; i <= spawns; i++)
        for (int j = 1; j <= n; avr[j] += spx[i][j], j++);
    for (int j = 1; j <= n; avr[j] /= (lf)spawns, j++);
    // Post-processing values
    for (int j = 1; j <= n; j++) {
        avr[j] *= mx_d; // .*
        avr[j] += center[j];
        if (avr[j] > -0.001 && avr[j] < 0.000)
            avr[j] = 0.0;
    }
    // Outputting the result
    for (int i = 1; i <= n; i++)
        printf("%.3Lf ", avr[i]);
    return 0;
}

from pydatagen import *
n = randrange(1, 11)
printf('%d \n' % n)
for i in range(0, n + 1):
    for j in range(0, n):
        out = randrange(-5000000, 5000000) * 0.001
        printf('%.3f ' % out)
    printf('\n')
fclose()