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;
}
View Code

 

posted @ 2016-03-01 10:02  诚叙  阅读(296)  评论(0编辑  收藏  举报