[JSOI2008]球形空间产生器

嘟嘟嘟

由题意可知,我们要求一个\(n\)元组\((x_1, x_2, x_3, \dots, x_n)\),满足
\[\sum _ {j = 1} ^ {n} (a_{ij} - x_j) ^ 2 = r ^ 2\]
对于\(\forall i \in [1, n]\)都成立。
这个式子说白了就是一个\(n\)元二次方程组,很显然我(们)不会。但是我们会\(n\)元线性方程组啊,能不能转化一下?
答案是能的。
很简单,只要相邻两个方程组作差就行了,这样就会把\({x_j} ^ 2\)这一项消掉。
然后套上高斯消元板子即可。
需要注意的是,新的方程组每一个方程中\(x_j\)的系数只有\(2 * (a_{i + 1, j} - a_{ij})\),剩下的都应该移到等式右侧累加到常数项,同时别忘了变号。

#include<cstdio>#include<iostream>#include<cmath>#include<algorithm>#include<cstring>#include<cstdlib>#include<cctype>#include<vector>#include<stack>#include<queue>using namespace std;#define enter puts("") #define space putchar(‘ ‘)#define Mem(a, x) memset(a, x, sizeof(a))#define rg registertypedef long long ll;typedef double db;const int INF = 0x3f3f3f3f;const db eps = 1e-8;const int maxn = 15;inline ll read(){ ll ans = 0; char ch = getchar(), last = ‘ ‘; while(!isdigit(ch)) {last = ch; ch = getchar();} while(isdigit(ch)) {ans = (ans << 1) + (ans << 3) + ch - ‘0‘; ch = getchar();} if(last == ‘-‘) ans = -ans; return ans;}inline void write(ll x){ if(x < 0) x = -x, putchar(‘-‘); if(x >= 10) write(x / 10); putchar(x % 10 + ‘0‘);}int n;db a[maxn][maxn], f[maxn][maxn], ans[maxn];int main(){ n = read(); for(int i = 1; i <= n + 1; ++i) for(int j = 1; j <= n; ++j) scanf("%lf", &a[i][j]); for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) { f[i][j] = 2.0 * (a[i][j] - a[i + 1][j]); f[i][n + 1] += a[i][j] * a[i][j] - a[i + 1][j] * a[i + 1][j]; } for(int i = 1; i <= n; ++i) { int pos = i; for(int j = i + 1; j <= n; ++j) if(fabs(f[j][i]) > fabs(f[pos][i])) pos = j; if(pos != i) swap(f[i], f[pos]); db tp = f[i][i]; if(fabs(tp) > eps) for(int j = i; j <= n + 1; ++j) f[i][j] /= tp; for(int j = i + 1; j <= n; ++j) { db tp = f[j][i]; for(int k = i; k <= n + 1; ++k) f[j][k] -= f[i][k] * tp; } } for(int i = n; i; --i) //回代 { ans[i] = f[i][n + 1]; for(int j = i - 1; j; --j) f[j][n + 1] -= f[i][n + 1] * f[j][i]; } for(int i = 1; i <= n; ++i) printf("%.3lf ", ans[i]); enter; return 0;}

相关文章