207. 球形空間產生器
阿新 • • 發佈:2022-04-14
題目連結
207. 球形空間產生器
有一個球形空間產生器能夠在 \(n\) 維空間中產生一個堅硬的球體。
現在,你被困在了這個 \(n\) 維球體中,你只知道球面上 \(n+1\) 個點的座標,你需要以最快的速度確定這個 \(n\) 維球體的球心座標,以便於摧毀這個球形空間產生器。
注意: 資料保證有唯一解。
輸入格式
第一行是一個整數 \(n\)。
接下來的 \(n+1\) 行,每行有 \(n\) 個實數,表示球面上一點的 \(n\) 維座標。
每一個實數精確到小數點後 \(6\) 位,且其絕對值都不超過 \(20000\)。
輸出格式
有且只有一行,依次給出球心的 \(n\) 維座標(\(n\) 個實數),兩個實數之間用一個空格隔開。
每個實數精確到小數點後 \(3\) 位。
資料範圍
\(1≤n≤10\)
輸入樣例:
2
0.0 0.0
-1.0 1.0
1.0 0.0
輸出樣例:
0.500 1.500
解題思路
高斯消元
設球心座標為 \((x_1,x_2,\dots,x_n)\),依題意,有如下方程組(\(n+1\) 個等式,\(n+1\) 個未知數):
\[\left\{\begin{array}{l} \left(a_{01}-x_{1}\right)^{2}+\left(a_{02}-x_{2}\right)^{2}+\cdots+\left(a_{0 n}-x_{n}\right)^{2}=R^{2} \\ \left(a_{11}-x_{1}\right)^{2}+\left(a_{12}-x_{2}\right)^{2}+\cdots+\left(a_{1 n}-x_{n}\right)^{2}=R^{2} \\ \cdots \\ \left(a_{n1}-x_{1}\right)^{2}+\left(a_{n2}-x_{2}\right)^{2}+\cdots+\left(a_{n n}-x_{n}\right)^{2}=R^{2} \end{array}\right. \]相鄰兩個等式作差,得:
此即為 \(n\)
- 先構造成如下形式(上三角矩陣):
\( \begin{bmatrix} 1 & & & \\ 0 & 1 & & \\ 0&0 & 1 & \end{bmatrix} \)
按對角線 \((r,c)\) 列舉,為了使除數不為 \(0\),找絕對值最大的 \(b[i][c]\),將對應的行換到 \(r\) 行,將 \(b[r][c]\) 化成 \(1\),每次按列將 \((r,c)\) 下面列消為 \(0\),
- 最後構造如下形式(簡化階梯型矩陣):
\( \begin{bmatrix} 1 &0 & 0 & \\ 0 & 1 & 0 & \\ 0 & 0& 1& \end{bmatrix} \)
按列消,從最後一列往前,最終 \(n+1\) 列即為答案
- 時間複雜度:\(O(n^3)\)
爬山法
程式碼
- 高斯消元
// Problem: 球形空間產生器
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/209/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=15;
double a[N][N],b[N][N];
int n;
void Gauss()
{
for(int r=1,c=1;r<=n;r++,c++)
{
int t=r;
for(int i=r+1;i<=n;i++)
if(fabs(b[i][c])>fabs(b[t][c]))t=i;
for(int i=c;i<=n+1;i++)swap(b[r][i],b[t][i]);
for(int i=n+1;i>=c;i--)b[r][i]/=b[r][c];
for(int i=r+1;i<=n;i++)
for(int j=n+1;j>=c;j--)b[i][j]-=b[i][c]*b[r][j];
}
for(int j=n;j>1;j--)
for(int i=j-1;i>=1;i--)
{
b[i][n+1]-=b[j][n+1]*b[i][j];
b[i][j]=0;
}
}
int main()
{
scanf("%d",&n);
for(int i=0;i<=n;i++)
for(int j=1;j<=n;j++)scanf("%lf",&a[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
b[i][j]=2*(a[i-1][j]-a[i][j]);
b[i][n+1]+=a[i-1][j]*a[i-1][j]-a[i][j]*a[i][j];
}
Gauss();
for(int i=1;i<=n;i++)printf("%.3lf ",b[i][n+1]);
return 0;
}