1. 程式人生 > >BZOJ 1013 [JSOI2008]球形空間產生器sphere

BZOJ 1013 [JSOI2008]球形空間產生器sphere

當前 消元 tail detail 未知數 int jsoi2008 ios 靠譜

這裏是題目的傳送門

題目的大意是比較好懂的,就是說給你一個(N + 1)個N維空間上的點,讓你求這個(N + 1)個點的圓心坐標。

拿到這道題目我首先想到的是模擬退火。。。

為什麽? 不為什麽

但是感覺這個正確率可能出現問題,因為這個題並不是求極值,所以只能通過其它的方法來判斷是否最優(比如說算標準差什麽的,但是這樣子真的不太靠譜)

又想到了我之前寫過一道模擬退火的題目,調了emmm20次吧,於是就沒敢寫。

這道題目裏有一個性質——即圓心的性質

圓心到每一個點的距離都相同,於是我們可以這樣子假設

假設答案為(x1,x2,x3,……,xn),當前這個點為(a1,a2,a3……,an),下一點為(b1,b2,b3……,bn)

我們可以列出方程

(a1 - x1) ^ 2 + (a2 - x2) ^ 2 + (a3 - x3) ^ 2 +……+(an - xn) ^ 2 = (b1 - x1) ^ 2 + (b2 - x2) ^ 2 + …… + (an - xn) ^ 2

化簡可得

2(a1 - b1) x1 + 2 (a2 - b2)x2 + …… +2(an - bn)xn=a1 ^ 2 + a2 ^ 2 +……+an ^ 2 - b1 ^ 2 - b2 ^ 2 - …… - bn ^ 2

我們一共有N + 1個點

所以我們可以列出N個方程

接下來就使用高斯消元

把所有的未知數解出來,由於數據保證有解,所以不會存在自由元

大家可以大膽地去做啦

技術分享圖片
 1 #include <cmath>
 2 #include <ctime>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <iostream>
 6 #include <algorithm>
 7 #define ll long long
 8 #define db double
 9 #define fo(i,x,y) for (int i=x; i<=y; i++)
10 #define pr(i,x,y) for (int i=x; i>=y; i--)
11
#define cl(a,x) memset(a,x,sizeof(a)) 12 13 using namespace std; 14 15 int N; 16 db Mat[15][15]; 17 db a[15][15]; 18 19 int main() 20 { 21 scanf("%d",&N); 22 cl(Mat,0); 23 fo(i,1,N + 1) 24 { 25 fo(j,1,N) 26 { 27 scanf("%lf",&a[i][j]); 28 if (i != 1) 29 { 30 Mat[i - 1][j]=2 * (a[i][j] - a[i - 1][j]); 31 Mat[i - 1][N + 1]+=a[i][j] * a[i][j] - a[i - 1][j] * a[i - 1][j]; 32 } 33 } 34 } 35 fo(i,1,N) 36 { 37 int T=i; 38 fo(j,i + 1,N) 39 { 40 if (fabs(Mat[j][i]) > fabs(Mat[T][i])) 41 { 42 T=j; 43 } 44 } 45 if (T != i) 46 { 47 fo(j,1,N + 1) 48 { 49 swap(Mat[i][j],Mat[T][j]); 50 } 51 } 52 fo(j,i + 1,N) 53 { 54 db X=Mat[j][i] / Mat[i][i]; 55 fo(k,i,N + 1) 56 { 57 Mat[j][k]-=Mat[i][k] * X; 58 } 59 } 60 } 61 pr(i,N,1) 62 { 63 fo(j,i + 1,N) 64 { 65 Mat[i][N + 1]-=Mat[j][N + 1] * Mat[i][j]; 66 } 67 Mat[i][N + 1]/=Mat[i][i]; 68 } 69 fo(i,1,N - 1) 70 { 71 printf("%.3f ",Mat[i][N + 1]); 72 } 73 printf("%.3f\n",Mat[N][N + 1]); 74 return 0; 75 }
View Code

BZOJ 1013 [JSOI2008]球形空間產生器sphere