线性方程组-高斯消元
P2455 [SDOI2006] 线性方程组
已知 n n n 元线性一次方程组。
{ a 1 , 1 x 1 + a 1 , 2 x 2 + ⋯ + a 1 , n x n = b 1 a 2 , 1 x 1 + a 2 , 2 x 2 + ⋯ + a 2 , n x n = b 2 ⋯ a n , 1 x 1 + a n , 2 x 2 + ⋯ + a n , n x n = b n \begin{cases} a_{1, 1} x_1 + a_{1, 2} x_2 + \cdots + a_{1, n} x_n = b_1 \\ a_{2, 1} x_1 + a_{2, 2} x_2 + \cdots + a_{2, n} x_n = b_2 \\ \cdots \\ a_{n,1} x_1 + a_{n, 2} x_2 + \cdots + a_{n, n} x_n = b_n \end{cases} ⎩ ⎨ ⎧a1,1x1+a1,2x2+⋯+a1,nxn=b1a2,1x1+a2,2x2+⋯+a2,nxn=b2⋯an,1x1+an,2x2+⋯+an,nxn=bn
请根据输入的数据,编程输出方程组的解的情况。
高斯消元是什么呢
枚举每一个未知数 也就是n列
利用第一个系数 将其他的系数全部消为0 (只剩最后一个肯定是消不掉的)
{ a x 1 + ⋯ = B 1 b x 2 + ⋯ = B 2 \begin{cases} ax_1+\cdots=B_1 \\ bx_2+\cdots=B_2 \end{cases} {ax1+⋯=B1bx2+⋯=B2
利用a消掉b
即第二行减去 b / a b/a b/a倍的第一行 --> b − b / a ∗ a = 0 b-b/a*a=0 b−b/a∗a=0
继续对第三行…第n行做同样的操作 这样就可以消掉其他行的这个未知数的系数
容易发现需要用double 可能存在丢精度的问题
只需要使 b / a b/a b/a变小 就可以让丢失的精度尽可能低 即找出最大的 a a a
只需要做一遍for循环 然后交换这两行即可
这样一定可以是最初矩阵转化为行阶梯型矩阵
最后只需要倒着遍历求解 然后回代即可
需要注意的是 判断为0不能 = = 0 ==0 ==0 因为小数会有精度误差的问题
判断解的个数
既然最后一定是行阶梯型矩阵
只需要在for循环的时候求矩阵的秩
我们用line表示当前访问到了哪个非0行 即目前矩阵的秩+1
即 a [ l i n e ] [ i ] a[line][i] a[line][i]如果 < e p s <eps <eps 此时矩阵的秩应该减去1 即line此时不应该+1
无穷多解 即零行是这样的:
0 0 0 0 ⋯ 0 0 \ 0 \ 0 \ 0 \cdots 0 0 0 0 0⋯0
无解 即零行是这样的
0 0 0 0 ⋯ b ( b ≠ 0 ) 0 \ 0 \ 0 \ 0 \cdots b \ (b\neq0) 0 0 0 0⋯b (b=0)
只需要从line遍历到n 判断一下即可
详见代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iomanip>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
//#include<random>
//#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define double long double
const double eps=1e-9;
void solve(){
int n;
cin>>n;
vector<vector<double>>a(n+10,vector<double>(n+10));
for(int i=1;i<=n;++i){
for(int j=1;j<=n+1;++j){
int x;cin>>x;
a[i][j]=x;
}
}
int line=1;
for(int i=1;i<=n;i++){
int maxn=line;
for(int j=line+1;j<=n;j++){
if(fabs(a[j][i])>fabs(a[maxn][i]))maxn=j;
}
swap(a[maxn],a[line]);
if(fabs(a[line][i])<eps)continue;
for(int j=line+1;j<=n;j++){
for(int k=n+1;k>=i;k--){
a[j][k]-=a[j][i]/a[line][i]*a[line][k];
}
}
line++;
}
for(int i=line;i<=n;i++){
if(fabs(a[i][n+1])>eps){
cout<<-1;//无解
return ;
}
}
if(line<=n){cout<<0;return ;}//无穷多解
for(int i=n;i>=1;i--){
for(int j=i+1;j<=n;j++){
a[i][n+1]-=a[i][j]*a[j][n+1];//回代
}
a[i][n+1]/=a[i][i];
}
for(int i=1;i<=n;i++)cout<<"x"<<i<<"="<<fixed<<setprecision(5)<<a[i][n+1]<<'\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int t=1;
// cin>>t;
while(t--)solve();
return 0;
}