高斯消元
高斯消元法用于解决 n 元一次加法方程组、异或方程组、同余方程组。
加法方程组
高斯消元法解决加法方程本质上是对我们小学学过的消元法一样。
需要用到矩阵初等行变换:
- 矩阵中可以任意交换两行的数值。
- 矩阵中可以对任意一行的每一列的值进行相同的初等运算 + - * / %。
其实这两个变换对应的操作就是确定主元(防溢出),以及消元过程。
高斯消元法解决加法方程组的过程:
- 将 n 元一次方程组填入矩阵,例如:\(x_1a_1 + x_2a_2 + x_3a_3 + ...+ x_na_n = c_1\)填入矩阵的第一行为\([x_1, x_2, x_3, ..., x_n, c_1]\)
- 确定主元(选取最大的防溢出),交换到第 i 行,注意要从第 0 行一直找到最后一行,因为前面可能出现自由元。
- 将主元所在行的所有元素同除主元。
- 利用主元所在行去消除其他行,注意不要把主元所在行消掉。
- 重复 2 - 4 步骤 n 次,直到矩阵变为单位矩阵(这个单位矩阵不包括最后一列)。
- 判断解的情况,下面记主元为x,最后一列为c,如果出现x = 1 -> c != 0,x即为所求; x = 0 -> c = 0,答案有无穷解;x = 0 -> c != 0,答案为无解。
高斯消元解决加法方程组
code:
#include <iostream>
#include <cmath>
using namespace std;
const int N = 110;
const double eps = 1e-7;
int n;
double a[N][N];
bool zero(double x)
{
return fabs(x) < eps;
}
int guass()
{
for(int i = 1; i <= n; i++)
{
// 确定主元
int aim = i;
for(int j = 1; j <= n; j++)
{
if(j < i && !zero(a[j][j])) continue;
if(fabs(a[j][i]) > fabs(a[aim][i])) aim = j;
}
// 判断是否为自由元
if(zero(a[aim][i])) return 0;
// 交换aim 和 i 行
for(int j = 1; j <= n + 1; j++) swap(a[aim][j], a[i][j]);
// 把第i行变为1
for(int j = n + 1; j >= i; j--) a[i][j] /= a[i][i];
// 消元
for(int j = 1; j <= n; j++)
{
if(i == j) continue;
double t = a[j][i];
for(int k = i; k <= n + 1; k++) a[j][k] -= a[i][k] * t;
}
}
return 1;
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n + 1; j++)
{
cin >> a[i][j];
}
}
int ret = guass();
if(ret)
{
for(int i = 1; i <= n; i++)
{
printf("%.2lf \n", a[i][n + 1]);
}
}
else cout << "No Solution" << endl;
return 0;
}
时间复杂度:\(O(n^3)\)
题目大意:有一个球形空间产生器能够在 n 维空间中产生一个坚硬的球体。现在,你被困在了这个 n 维球体中,你只知道球面上 n+1 个点的坐标,你需要以最快的速度确定这个 n 维球体的球心坐标,以便于摧毁这个球形空间产生器。
【解题】:
- 球心:到球面上任意一点距离都相等的点。
- 距离:设两个 n 维空间上的点 A,B 的坐标为 (a1,a2,⋯,an),(x1,x2,...,xn),则 A,B 的距离定义为:
\(dist = \sqrt{(a_1 - x_1)^ 2 + (a_2 - x_2)^ 2+ (a_3 - x_3)^2 +...+(a_n - x_n)^2}\)
设第一个点的坐标为(tmp1,tmp2,tmp3,...tmpn),之后每行的坐标为(x1,x2,x3,...xn)
则可以的出每行的方程组:\([2*(x_1 - tmp_1), 2*(x_2 - tmp_2),2*(x_3-tmp_3),...,2*(x_n-tmp_n), \sum_{i=1}^n x^2-\sum_{i=1}^n tmp^2]\)
code:
#include <iostream>
#include <cmath>
using namespace std;
typedef long long LL;
#define endl '\n'
const int N = 15;
const double eps = 1e-7;
int n;
double a[N][N];
double tmp[N];
bool zero(double x)
{
return fabs(x) < eps;
}
void guass()
{
for(int i = 1; i <= n; i++)
{
int aim = i;
for(int j = 1; j <= n; j++)
{
if(j < i && !zero(a[j][j])) continue;
if(fabs(a[aim][i]) < fabs(a[j][i])) aim = j;
}
for(int j = 1; j <= n + 1; j++) swap(a[i][j], a[aim][j]);
for(int j = n + 1; j >= i; j--) a[i][j] /= a[i][i];
for(int j = 1; j <= n; j++)
{
if(j == i) continue;
double t = a[j][i] / a[i][i];
for(int k = i; k <= n + 1; k++) a[j][k] -= a[i][k] * t;
}
}
}
void solve()
{
cin >> n;
for(int i = 1; i <= n; i++) cin >> tmp[i];
for(int i = 1; i <= n; i++)
{
double SquR = 0;
for(int j = 1; j <= n; j++)
{
double x; cin >> x;
a[i][j] = 2 * (x - tmp[j]);
SquR += x * x - tmp[j] * tmp[j];
}
a[i][n + 1] = SquR;
}
// for(int i = 1; i <= n; i++)
// {
// for(int j = 1; j <= n + 1; j++)
// {
// cout << a[i][j] << " ";
// }
// cout << endl;
// }
guass();
for(int i = 1; i <= n; i++) printf("%.3lf ", a[i][n + 1]);
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T = 1;
// cin >> T;
while(T--)
{
solve();
}
return 0;
}
浙公网安备 33010602011771号