【BZOJ1013】[JSOI2008] 球形空间产生器(高斯消元)

点此看题面

大致题意: 给定一个 n n n维球体上的 n + 1 n+1 n+1个点,请你求出这个球体的圆心的位置。


列出方程

这一看就是一道解方程题

我们可以设这个球体的圆心的位置为 ( x 1 , x 2 , . . x n ) (x_1,x_2,..x_n) (x1,x2,..xn),并设每个点到圆心的距离为 d i s dis dis

借助题目中给出的公式,我们可以得到以下方程:

{ ( x 1 − a 1 , 1 ) 2 + ( x 2 − a 1 , 2 ) 2 + . . . + ( x n − a 1 , n ) 2 = d i s ( x 1 − a 2 , 1 ) 2 + ( x 2 − a 2 , 2 ) 2 + . . . + ( x n − a 2 , n ) 2 = d i s . . . . . . ( x 1 − a n + 1 , 1 ) 2 + ( x 2 − a n + 1 , 2 ) 2 + . . . + ( x n − a n + 1 , n ) 2 = d i s \begin{cases}\sqrt{(x_1-a_{1,1})^2+(x_2-a_{1,2})^2+...+(x_n-a_{1,n})^2}=dis\\\sqrt{(x_1-a_{2,1})^2+(x_2-a_{2,2})^2+...+(x_n-a_{2,n})^2}=dis\\......\\\sqrt{(x_1-a_{n+1,1})^2+(x_2-a_{n+1,2})^2+...+(x_n-a_{n+1,n})^2}=dis\end{cases} (x1a1,1)2+(x2a1,2)2+...+(xna1,n)2 =dis(x1a2,1)2+(x2a2,2)2+...+(xna2,n)2 =dis......(x1an+1,1)2+(x2an+1,2)2+...+(xnan+1,n)2 =dis


方程的转化

原方程看起来十分麻烦,又有平方,又有开方,很难解,因此我们要将它转化一下。

将方程两边同时平方,可得:

{ ( x 1 − a 1 , 1 ) 2 + ( x 2 − a 1 , 2 ) 2 + . . . + ( x n − a 1 , n ) 2 = d i s 2 ( x 1 − a 2 , 1 ) 2 + ( x 2 − a 2 , 2 ) 2 + . . . + ( x n − a 2 , n ) 2 = d i s 2 . . . . . . ( x 1 − a n + 1 , 1 ) 2 + ( x 2 − a n + 1 , 2 ) 2 + . . . + ( x n − a n + 1 , n ) 2 = d i s 2 \begin{cases}(x_1-a_{1,1})^2+(x_2-a_{1,2})^2+...+(x_n-a_{1,n})^2=dis^2\\(x_1-a_{2,1})^2+(x_2-a_{2,2})^2+...+(x_n-a_{2,n})^2=dis^2\\......\\(x_1-a_{n+1,1})^2+(x_2-a_{n+1,2})^2+...+(x_n-a_{n+1,n})^2=dis^2\end{cases} (x1a1,1)2+(x2a1,2)2+...+(xna1,n)2=dis2(x1a2,1)2+(x2a2,2)2+...+(xna2,n)2=dis2......(x1an+1,1)2+(x2an+1,2)2+...+(xnan+1,n)2=dis2

但是,这些方程全部都是二次方程,好像非常难做。

因此,我们考虑将每个方程展开:

{ x 1 2 − 2 a 1 , 1 x 1 + a 1 , 1 2 + x 2 2 − 2 a 1 , 2 x 2 + a 1 , 2 2 + . . . + x n 2 − 2 a 1 , n x n + a 1 , n 2 = d i s 2 x 1 2 − 2 a 2 , 1 x 1 + a 2 , 1 2 + x 2 2 − 2 a 2 , 2 x 2 + a 2 , 2 2 + . . . + x n 2 − 2 a 2 , n x n + a 2 , n 2 = d i s 2 . . . . . . x 1 2 − 2 a n + 1 , 1 x 1 + a n + 1 , 1 2 + x 2 2 − 2 a n + 1 , 2 x 2 + a n + 1 , 2 2 + . . . + x n 2 − 2 a n + 1 , n x n + a n + 1 , n 2 = d i s 2 \begin{cases}x_1^2-2a_{1,1}x_1+a_{1,1}^2+x_2^2-2a_{1,2}x_2+a_{1,2}^2+...+x_n^2-2a_{1,n}x_n+a_{1,n}^2=dis^2\\x_1^2-2a_{2,1}x_1+a_{2,1}^2+x_2^2-2a_{2,2}x_2+a_{2,2}^2+...+x_n^2-2a_{2,n}x_n+a_{2,n}^2=dis^2\\......\\x_1^2-2a_{n+1,1}x_1+a_{n+1,1}^2+x_2^2-2a_{n+1,2}x_2+a_{n+1,2}^2+...+x_n^2-2a_{n+1,n}x_n+a_{n+1,n}^2=dis^2\\\end{cases} x122a1,1x1+a1,12+x222a1,2x2+a1,22+...+xn22a1,nxn+a1,n2=dis2x122a2,1x1+a2,12+x222a2,2x2+a2,22+...+xn22a2,nxn+a2,n2=dis2......x122an+1,1x1+an+1,12+x222an+1,2x2+an+1,22+...+xn22an+1,nxn+an+1,n2=dis2

这时候,我们显然可以看出每个方程中左边都有 x 1 2 + x 2 2 + . . . + x n 2 x_1^2+x_2^2+...+x_n^2 x12+x22+...+xn2,右边都有 d i s 2 dis^2 dis2,不难想到,将第 1 ∼ n 1\sim n 1n个方程分别减去第 n + 1 n+1 n+1个方程,便可以得到一个新的方程组,而且是一次的:

{ 2 ( a n + 1 , 1 − a 1 , 1 ) ⋅ x 1 + . . . + 2 ( a n + 1 , n − a 1 , n ) ⋅ x n = a n + 1 , 1 2 − a 1 , 1 2 + . . . + a n + 1 , n 2 − a 1 , n 2 2 ( a n + 1 , 1 − a 2 , 1 ) ⋅ x 1 + . . . + 2 ( a n + 1 , n − a 2 , n ) ⋅ x n = a n + 1 , 1 2 − a 2 , 1 2 + . . . + a n + 1 , n 2 − a 2 , n 2 . . . 2 ( a n + 1 , 1 − a n , 1 ) ⋅ x 1 + . . . + 2 ( a n + 1 , n − a n , n ) ⋅ x n = a n + 1 , 1 2 − a n , 1 2 + . . . + a n + 1 , n 2 − a n , n 2 \begin{cases}2(a_{n+1,1}-a_{1,1})·x_1+...+2(a_{n+1,n}-a_{1,n})·x_n=a_{n+1,1}^2-a_{1,1}^2+...+a_{n+1,n}^2-a_{1,n}^2\\2(a_{n+1,1}-a_{2,1})·x_1+...+2(a_{n+1,n}-a_{2,n})·x_n=a_{n+1,1}^2-a_{2,1}^2+...+a_{n+1,n}^2-a_{2,n}^2\\...\\2(a_{n+1,1}-a_{n,1})·x_1+...+2(a_{n+1,n}-a_{n,n})·x_n=a_{n+1,1}^2-a_{n,1}^2+...+a_{n+1,n}^2-a_{n,n}^2\end{cases} 2(an+1,1a1,1)x1+...+2(an+1,na1,n)xn=an+1,12a1,12+...+an+1,n2a1,n22(an+1,1a2,1)x1+...+2(an+1,na2,n)xn=an+1,12a2,12+...+an+1,n2a2,n2...2(an+1,1an,1)x1+...+2(an+1,nan,n)xn=an+1,12an,12+...+an+1,n2an,n2

由于 a a a数组是题目中给出的,我们就可以直接高斯消元了。

L i n k Link Link

高斯消元详见博客高斯消元入门


代码
#include<bits/stdc++.h>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define abs(x) ((x)<0?-(x):(x))
#define LL long long
#define ull unsigned long long
#define N 10
using namespace std;
int n;
namespace Gauss
{
	const double eps=1e-10;//eps是一个极小值,防止精度误差
	double a[N+5][N+5],s[N+5];
	inline void swap(double &x,double &y)
	{
		double t=x;x=y,y=t;
	}
	inline void GetData()//将读入的数据转化为方程的系数
	{
		register int i,j;
		for(i=1;i<=n+1;++i) for(j=1;j<=n;++j) scanf("%lf",&a[i][j]);
		for(i=1;i<=n;++i) for(s[i]=0,j=1;j<=n;++j) 
			s[i]+=a[n+1][j]*a[n+1][j]-a[i][j]*a[i][j],a[i][j]=2*(a[n+1][j]-a[i][j]);
	}
	inline void Find_line(int x)//找到一个行数大于等于x且第x个元素系数不为0的方程,将其移至第x行
	{
		register int i=x,j;
		while(i<=n&&fabs(a[i][x])<eps) ++i;
		for(j=1;j<=n;++j) swap(a[x][j],a[i][j]);
	}
	inline void PrintAns()
	{
		register int i,j,k;
		for(i=1;i<=n;++i)
		{
			for(Find_line(i),j=i+1;j<=n;++j)//消去[i+1~n]中每一行第i个元素
			{
				register double delta=-a[j][i]/a[i][i];
				for(s[j]+=s[i]*delta,k=i;k<=n;++k) a[j][k]+=a[i][k]*delta;
			}
		}
		for(i=n;i;--i) for(s[i]/=a[i][i],j=i-1;j;--j) s[j]-=a[j][i]*s[i];//计算出第i个未知数的值,并将第i个元素的值代入第1~i-1行的式子中消去第i个未知数
		for(i=1;i<=n;++i) printf("%.3lf ",s[i]);//输出每一个未知数的值
	}
}
int main()
{
	return scanf("%d",&n),Gauss::GetData(),Gauss::PrintAns(),0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值