BZOJ1013 [JSOI2008]球形空间产生器sphere
AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1013
感觉还是比较水吧,按照给的提示的话,比较好想的就是加入一个球心坐标,列出n+1个方程。
然后你也可以把半径当成第n+1个变量,但是这样的话,球心左边中就有根号下的二次项了。
所以我们就想把二次项减掉,所以首先把每个等式的两边都平方一下,然后相邻的相减一下就好了。
这样的话,不仅消了二次项,而且也少了半径这个变量,后面就是O(n^3)的高斯消元了...
而且一定是唯一解,算是高斯消元入门题吧
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=12; const double eps=1e-6; int n; double rec_x[maxn]; double d[maxn][maxn]; double w[maxn][maxn]; void Swap(int x,int y,int j){ double t; for(int i=j;i<=n+1;i++) t=w[x][i],w[x][i]=w[y][i],w[y][i]=t; } void gauss(){ int i,j; for(i=1,j=1;i<=n && j<=n;i++,j++){ int max_r=i; for(int k=i+1;k<=n;k++) if(fabs(w[k][j])>fabs(w[max_r][j])+eps) max_r=k; if(fabs(w[max_r][j])<eps) {i--;continue;} if(i!=max_r) Swap(i,max_r,j); for(int k=i+1;k<=n;k++){ double t=w[k][j]/w[i][j]; for(int l=j;l<=n+1;l++) w[k][l]-=t*w[i][l]; } } for(int i=n;i>=1;i--) if(fabs(w[i][i])>0){ double ans_c=w[i][n+1]; for(int j=i+1;j<=n;j++) ans_c-=w[i][j]*rec_x[j]; rec_x[i]=ans_c/w[i][i]; } } int main(){ #ifndef ONLINE_JUDGE freopen("1013.in","r",stdin); freopen("1013.out","w",stdout); #endif scanf("%d",&n); for(int i=1;i<=n+1;i++) for(int j=1;j<=n;j++) scanf("%lf",&d[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) w[i][j]=-2*d[i][j]+2*d[i+1][j], w[i][n+1]+=d[i+1][j]*d[i+1][j]-d[i][j]*d[i][j]; gauss(); for(int i=1;i<n;i++) printf("%.3lf ",rec_x[i]); printf("%.3lf",rec_x[n]); return 0; }