P4035 [JSOI2008]球形空间产生器
P4035 [JSOI2008]球形空间产生器
题目
题目大意
给出n维空间上的n+1个点,且这些店都在一个圆的表面,求圈心坐标.
定义:
- 
球心:到球面上任意一点距离都相等的点。 
- 
两点间距离公式 
\[A(x_1,x_2,x_3,x_4,\cdots x_n) 
\]
\[B(y_1,y_2,y_3,y_4,\cdots y_n) 
\]
\[distance:\sqrt[2]{\sum_{i=1}^{n}(x_i-y_i)^2} 
\]
题目看上去应该就是解方程了。
我们可以使用gauss消元法。
不过问题就来了。这是一个二次多元方程组。而我们的gauss只能解决一次。而且gauss的前提是有n个未知数,我们必须有n个方程。(当然有些不严谨)
我们就要考虑移项和再设一个未知数。
原方程中的一个:我们先设一个数,r。表示根据圆的标准方程算出来的半径
A为一个点,R为圆心
\[A(x_1,x_2,x_3,x_4,\cdots x_n)
\]
\[R(y_1,y_2,y_3,y_4,\cdots y_n)
\]
\[\sum_{i=1}^{n}(x_i-y_i)^2=r^2
\]
\[\sum_{i=1}^{n}x_i^2-\sum_{i=1}^{n}2x_iy_i+\sum_{i=1}^{n}y_i^2=r^2
\]
请注意这里的A的坐标都是已知量。而r和R的坐标不是
然后我们移项
\[-\sum_{i=1}^{n}2x_iy_i+(\sum_{i=1}^{n}y_i^2-r^2)=-\sum_{i=1}^{n}x_i^2
\]
最绕的一步来了
我们将括号内的整体代换(或看成一个未知数)
这样就有n+1个未知数来了。而且我们解出方程来后,我们只需要前n个未知数。后面我们后面设的未知数虽然解出来了。但是没有什么用。只是我们一个辅助变量
同时,这个题也告诉我们一些小技巧。
- 出题人不可能多给条件。有些是要我们自己设的
- 遇到二次方程。可以考虑拆括号和移项。然后进行还原达到降幂的目的
#include<cstdio> 
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
double map[15][15];
double ans[15];
int n;
void gauss()
{
	for(int i=1;i<=n+1;i++)
	{
		int r=i;
		for(int j=i+1;j<=n+1;j++)
			if(fabs(map[r][i])<fabs(map[j][i]))
				r=j;
		if(r!=i)
			for(int j=i;j<=n+2;j++)
				swap(map[i][j],map[r][j]);
		double div=map[i][i]; 
		for(int j=i;j<=n+2;j++)
			map[i][j]/=div;
		for(int j=i+1;j<=n+1;j++)
		{
			div=map[j][i];
			for(int k=i;k<=n+2;k++)
				map[j][k]-=div*map[i][k];
		}
	}
	ans[n+1]=map[n+1][n+2];
	for(int i=n;i>=1;i--)
	{
		ans[i]=map[i][n+2];
		for(int j=i+1;j<=n+1;j++)
			ans[i]-=map[i][j]*ans[j];
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n+1;i++)
	{
		double data;
		for(int j=1;j<=n;j++) 
		{
			scanf("%lf",&data);
			map[i][j]=-2.0*data;
			map[i][n+2]-=data*data;
		}
		map[i][n+1]=1;
	}
	gauss();
	printf("%.3lf",ans[1]);
	for(int i=2;i<=n;i++)
		printf(" %.3lf",ans[i]);
}

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号