1. 程式人生 > 實用技巧 >P4035 [JSOI2008]球形空間產生器

P4035 [JSOI2008]球形空間產生器

題目連結

題目大意:給定球面上 \(n+1\) 個點的座標,求球心的座標?

總體思路:推柿子+高斯消元

已知 \(n\) 維空間上的兩個點座標為 \((a_1,a_2,a_3...a_n)\)\((b_1,b_2,b_3...b_n)\),那麼他們的距離為:
\(dis=\sqrt{(a_1-b_1)^2+(a_2-b_2)^2+...+(a_n-b_n)^2}\)

那麼這就是圓心到圓上一點的距離了,也就是半徑,稱為 \(r\)

\[\sqrt{(a_1-b_1)^2+(a_2-b_2)^2+...+(a_n-b_n)^2}=r \]

\[(a_1-b_1)^2+(a_2-b_2)^2+...+(a_n-b_n)^2=r^2 \]

\[(a_1^2-2a_1b_1+b_1^2)+(a_2^2-2a_2b_2+b_2^2)+...+(a_n^2-2a_nb_n+b_n^2)=r^2 \]

\[(a_1^2+a_2^2+...+a_n^2)-(2a_1b_1+2a_2b_2+...+2a_nb_n)+(b_1^2+b_2^2+...+b_n^2)=r^2 \]

\[-(2a_1b_1+2a_2b_2+...+2a_nb_n)+(b_1^2+b_2^2+...+b_n^2)-r^2=-(a_1^2+a_2^2+...+a_n^2) \]

\[(2a_1b_1+2a_2b_2+...+2a_nb_n)+(r^2-(b_1^2+b_2^2+...+b_n^2))=(a_1^2+a_2^2+...+a_n^2) \]

可以發現,這個式子的右邊是一個常數,左邊有 \(n+1\) 項(\(n\)\(2a_ib_i\) 和一個係數為 \(1\)\((r^2-(b_1^2+b_2^2+...+b_n^2))\)

\[[ 2a_1 , 2a_2 , ... , 2a_n | a_1^2+a_2^2+...+a_n^2 ] \]

就可以用高斯消元啦,讀入時注意一下就行了,程式碼如下:

#include<bits/stdc++.h>
using namespace std;
int n;
double a[15][15],ans[15],in,add;
int main(){
	cin>>n;
	for(int i=1;i<=n+1;++i){
		for(int j=1;j<=n;++j){
			cin>>in;
			add+=in*in;
			a[i][j]=2*in;
		}
		a[i][n+1]=1;
		a[i][n+2]=add;add=0;
	}
	for(int i=1;i<=n+1;++i){
		int MAX=i;
		for(int j=i+1;j<=n+1;++j){
			if(fabs(a[j][i])>fabs(a[MAX][i])){
				MAX=j;
			}
		}
		if(MAX!=i)swap(a[i],a[MAX]);
		double d=a[i][i];
		for(int j=i;j<=n+2;++j){
			a[i][j]/=d;
		}
		for(int j=i+1;j<=n+1;++j){
			d=a[j][i];
		    for(int k=i;k<=n+2;++k){
		    	a[j][k]-=a[i][k]*d;
			}
		}
	}
	ans[n+1]=a[n+1][n+2];
	for(int i=n;i>=1;--i){
		ans[i]=a[i][n+2];
		for(int j=i+1;j<=n+1;++j){
			ans[i]-=a[i][j]*ans[j];
		}
	}
	for(int i=1;i<=n;++i){
		cout<<fixed<<setprecision(3)<<ans[i]<<" ";
	}
	return 0;
}