您的位置:首页 > Web前端 > JavaScript

[bzoj1013](JSOI2008)球形空间产生器sphere(高斯消元)

2015-03-26 18:09 453 查看

Description

有一个球形空间产生器能够在n维空间中产生一个坚硬的球体。现在,你被困在了这个n维球体中,你只知道球面上n+1个点的坐标,你需要以最快的速度确定这个n维球体的球心坐标,以便于摧毁这个球形空间产生器。

Input

第一行是一个整数,n。接下来的n+1行,每行有n个实数,表示球面上一点的n维坐标。每一个实数精确到小数点后6位,且其绝对值都不超过20000。

Output

有且只有一行,依次给出球心的n维坐标(n个实数),两个实数之间用一个空格隔开。每个实数精确到小数点后3位。数据保证有解。你的答案必须和标准输出一模一样才能够得分。

Sample Input

2

0.0 0.0

-1.0 1.0

1.0 0.0

Sample Output

0.500 1.500

HINT

数据规模:

对于40%的数据,1<=n<=3

对于100%的数据,1<=n<=10

提示:给出两个定义:

1、 球心:到球面上任意一点距离都相等的点。

2、 距离:设两个n为空间上的点A, B的坐标为$(a_1, a_2, …, a_n), (b_1, b_2, …, b_n)$,则AB的距离定义为:$$dist = \sqrt{ (a_1-b_1)^2 + (a_2-b_2)^2 + … + (a_n-b_n)^2 }$$

分析

设球心坐标为$(x_1, x_2, ... , x_n)$,根据定义可以列出方程组:

$$ \forall i,j \in [1,n+1]: \sum_{k=1}^N (x_k - a_{ik})^2 = \sum_{k=1}^N (x_k - a_{jk})^2$$.

展开后移项相减,得到

$$\sum_{k=1}^N 2(a_{ik} - a_{jk})x_k = a_{ik}^2 - a_{jk}^2 $$

由于变量有N个,我们只需选取其中N组线性无关(或可以使所有无向边(i,j)构成一棵树)的(i,j)方程来求解即可。

题目本身不难,可是为学校OJ造测试数据这种事简直醉人……我的做法是先随机出一个N维向量作为答案,再随机出半径R,接着循环N+1次,每次随机一个N-1维向量,求出这条直线与球的交点……最终还要运行一遍本题的高斯消元判断这些点是否线性相关……

好吧其实真正的问题是我太水了……敲错了datamaker调试了好久= =

1 /**************************************************************
2 Problem: 1013
3 User: AsmDef
4 Language: C++
5 Result: Accepted
6 Time:0 ms
7 Memory:1272 kb
8 ****************************************************************/
9
//Asm_Def
#include <iostream>
#include <cctype>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
template<typename T>inline void getd(T &x){
char c = getchar();
bool minus = 0;
while(!isdigit(c) && c != '-')c = getchar();
if(c == '-')minus = 1, c = getchar();
x = c - '0';
while(isdigit(c = getchar()))x = x * 10 + c - '0';
if(minus)x = -x;
}
/*======================================================*/
const double eps = 1e-12;
double *Eq[11], Ans[11];
int N;
inline void init(){
double a, P[11][12];
getd(N);int i, j;
for(j = 0;j < N;++j)scanf("%lf", *P + j);
for(i = 1;i <= N;++i){
for(j = 0;j < N;++j)
scanf("%lf", P[i] + j);
P[i-1]
= 0;
for(j = 0;j < N;++j){
a = P[i-1][j] + P[i][j];
P[i-1][j] = P[i][j] - P[i-1][j];
P[i-1]
+= a * P[i-1][j] / 2.0;
}
Eq[i-1] = P[i-1];
}
}
inline void solve(){
int i, j, k;
double frac;
for(i = 0;i < N;++i){
for(j = i+1;j < N;++j)
if(fabs(Eq[i][i]) < fabs(Eq[j][i]))swap(Eq[i], Eq[j]);

if(fabs(Eq[i][i]) < eps){
cout << "No Answer" << endl;
exit(1);
}
for(j = i+1;j < N;++j){
if(fabs(frac = Eq[j][i] / Eq[i][i]) < eps)continue;
Eq[j][i] = 0;
for(k = i+1;k <= N;++k)
Eq[j][k] -= frac * Eq[i][k];
}
}
for(i = N-1;i >= 0;--i){
Ans[i] = Eq[i]
/ Eq[i][i];
for(j = 0;j < i;++j)
Eq[j]
-= Eq[j][i] * Ans[i];
}
for(i = 0;i < N;++i)
printf("%.3lf%c", Ans[i], i == N-1 ? '\n' : ' ');
}
int main(){
#if defined DEBUG
//freopen("test", "r", stdin);
#else
//freopen("bzoj_1013.in", "r", stdin);
//freopen("bzoj_1013.out", "w", stdout);
#endif
init();
solve();

#if defined DEBUG
//cout << endl << (double)clock()/CLOCKS_PER_SEC << endl;
#endif
return 0;
}高斯消元
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: