洛谷题单指南-基础线性代数-P4035 [JSOI2008] 球形空间产生器

原题链接:https://www.luogu.com.cn/problem/P4035

题意解读:已知n维空间的n+1个点,求圆心坐标。

解题思路:(题解由Chatgpt生成)

image

image

image

借助每相邻两个点,一共可以得到n个这样的方程,n个未知数,可以使用高斯消元求解。

矩阵:a[i][j] = 2*(p[i+1][j]-p[i][j])

右侧:a[i][n+1] = sum(p[i+1][j]^2 - p[i][j]^2)

得到一个:n × (n+1)的增广矩阵。

100分代码:(代码由Chatgpt生成)

#include <bits/stdc++.h>
using namespace std;

const int N = 20;
const double EPS = 1e-8;

// a 为高斯消元用的增广矩阵,规模 n * (n+1)
// p 为输入的点坐标,共 n+1 个点,每个点是 n 维
double a[N][N];
double p[N][N];
int n; // 维度 n,同时未知数个数也是 n

int gauss()
{
    // 行指针:当前要处理的主元行
    int row = 1;

    for(int col = 1; col <= n; col++)
    {
        // 选主元:在当前列 col 中寻找绝对值最大的行
        int t = row;

        for(int i = row + 1; i <= n; i++)
            if(fabs(a[i][col]) > fabs(a[t][col]))
                t = i;

        // 主元接近 0,说明该列无法作为主元,跳过
        if(fabs(a[t][col]) < EPS) continue;

        // 将主元行交换到当前行
        for(int i = col; i <= n + 1; i++)
            swap(a[t][i], a[row][i]);

        // 把主元归一化,使 a[row][col] 变为 1
        for(int i = n + 1; i >= col; i--)
            a[row][i] /= a[row][col];

        for(int i = 1; i <= n; i++)
        {
            if(i == row) continue;

            // 用当前主元行消去其他行的该列
            for(int j = n + 1; j >= col; j--)
                a[i][j] -= a[row][j] * a[i][col];
        }

        // 处理下一行
        row++;
    }

    // 若未能形成 n 个主元行,检查是否有矛盾行
    if(row <= n)
    {
        for(int i = row; i <= n; i++)
            if(fabs(a[i][n + 1]) > EPS)
                return -1;

        // 存在自由元,返回 0
        return 0;
    }

    // 唯一解
    return 1;
}

int main()
{
    cin >> n;

    // 输入 n+1 个点,每个点 n 维
    for(int i = 1; i <= n + 1; i++)
        for(int j = 1; j <= n; j++)
            cin >> p[i][j];

    // 构造线性方程组:
    // 由 |x - p_i|^2 = |x - p_{i+1}|^2 推得
    // 2 * (p_{i+1} - p_i) · x = |p_{i+1}|^2 - |p_i|^2
    // 共 n 个方程,n 个未知数(x 的各维坐标)
    for(int i = 1; i <= n; i++)
    {
        // 系数部分
        for(int j = 1; j <= n; j++)
            a[i][j] = 2 * (p[i + 1][j] - p[i][j]);

        double rhs = 0;

        // 常数项:平方和之差
        for(int j = 1; j <= n; j++)
            rhs += p[i + 1][j] * p[i + 1][j] - p[i][j] * p[i][j];

        a[i][n + 1] = rhs;
    }

    // 求解增广矩阵
    gauss();

    // 输出解(球心坐标),保留三位小数
    for(int i = 1; i <= n; i++)
        printf("%.3lf ", a[i][n + 1]);

    return 0;
}

 

posted @ 2026-03-16 15:59  hackerchef  阅读(1)  评论(0)    收藏  举报