高斯消元法
Posted Harris-H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高斯消元法相关的知识,希望对你有一定的参考价值。
高斯消元法
法1:高斯-约旦消元
思路
A X = B AX=B AX=B
将 A , B A,B A,B同时进行初等变换,将 A A A变为对角线都为 1 1 1其他为 0 0 0的矩阵,则此时的 B B B就是 X X X。
从第一列开始,每次把 a [ i ] [ i ] = 1 a[i][i]=1 a[i][i]=1,其他变为 0 0 0。
流程
- 从第一列开始。
- 对每列 i i i在 [ i , n ] [i,n] [i,n]找到最大的 a [ j ] [ i ] , j ∈ [ i , n ] a[j][i],j\\in [i,n] a[j][i],j∈[i,n],这里从 i i i开始是因为 [ 1 , i − 1 ] [1,i-1] [1,i−1]的 1 1 1已经构造好了,不能在进行两行交换破坏结构。
- 如果此时最大值 a [ i ] [ i ] = 0 a[i][i]=0 a[i][i]=0说明该列都为 0 0 0无解。
- 否则用该行去抵消其他行,使得该行的非 i i i列都为 0 0 0。
时间复杂度: O ( n 3 ) O(n^3) O(n3)
P3389 code
int n;
double a[N][N];
void Gauss(){ //O(n^3)
rep(i,1,n){
int mx=i;
rep(j,i+1,n){
if(fabs(a[j][i])>fabs(a[mx][i])) mx=j;
}
rep(j,1,n+1) swap(a[i][j],a[mx][j]);
if(!a[i][i]) return (void)puts("No Solution");
rep(j,1,n){
if(j!=i){
double x=a[j][i]/a[i][i];
rep(k,i+1,n+1)
a[j][k]-=x*a[i][k];
}
}
}
rep(i,1,n) printf("%.2f\\n",a[i][n+1]/a[i][i]);
}
int main(){
scanf("%d",&n);
rep(i,1,n)
rep(j,1,n+1) scanf("%lf",&a[i][j]);
Gauss();
return 0;
}
法2 高斯消元(回代)
与法1不同的是,该方法没有化为对角为1的矩阵,而是逐个带入消元,最终求得 a n s n ans_n ansn,然后往回代,倒着求出 a n s n − 1 , a n s n − 2 … , a 1 ans_{n-1},ans_{n-2}\\dots,a_1 ansn−1,ansn−2…,a1。
int n;
double a[N][N],ans[N];
void Gauss(){ //O(n^3)
rep(i,1,n){
int mx=i;
rep(j,i+1,n){
if(fabs(a[j][i])>fabs(a[mx][i])) mx=j;
}
if(mx!=i) swap(a[mx],a[i]);
if(!a[i][i]) return (void)puts("No Solution");
double x=a[i][i];
rep(j,i,n+1) a[i][j]/=x;
rep(j,i+1,n){
x=a[j][i];
rep(k,i,n+1) a[j][k]-=a[i][k]*x;
}
}
ans[n]=a[n][n+1];
per(i,n-1,1){ //回代
ans[i]=a[i][n+1];
rep(j,i+1,n)
ans[i]-=a[i][j]*ans[j];
}
rep(i,1,n) printf("%.2f\\n",ans[i]);
}
int main(){
scanf("%d",&n);
rep(i,1,n)
rep(j,1,n+1) scanf("%lf",&a[i][j]);
Gauss();
return 0;
}
矩阵求逆
同样是利用高斯-约旦消元.
A A − 1 = E AA^{-1}=E AA−1=E
构造矩阵 [ A E ] [AE] [AE] ,通过初等变换为: [ E A − 1 ] [EA^{-1}] [EA−1].
时间复杂度: O ( n 3 ) O(n^3) O(n3)
code
int n;
ll a[N][N];
ll ksm(ll a,ll n,ll m=mod){
ll ans=1;
while(n){
if(n&1) ans=ans*a%m;
a=a*a%m;
n>>=1;
}
return ans;
}
void Inv_Matrix(){ //O(n^3)
int m=n<<1;
rep(i,1,n){
int mx=i;
rep(j,i+1,n){
if(a[j][i]>a[mx][i]) mx=j;
}
if(i!=mx) swap(a[i],a[mx]);
if(!a[i][i]) return (void)puts("No Solution");
ll x=ksm(a[i][i],mod-2);
rep(j,1,n){
if(j!=i){
ll y=a[j][i]*x%mod;
rep(k,i+1,m)
(a[j][k]-=y*a[i][k]%mod)%=mod;
}
}
rep(j,1,m) a[i][j]=a[i][j]*x%mod;
}
rep(i,1,n){
rep(j,n+1,m) printf("%lld ",(a[i][j]%mod+mod)%mod);
printf("\\n");
}
}
int main(){
scanf("%d",&n);
rep(i,1,n){
rep(j,1,n) scanf("%lld",&a[i][j]);
a[i][i+n]=1;
}
Inv_Matrix();
return 0;
}
高斯消元判断是否多解,无解,唯一解
利用传统的高斯消元即可.
时间复杂度: O ( n 3 ) O(n^3) O(n3)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=55,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define x first
#define y second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define ios ios::sync_with_stdio(false),cin.tie(0)
void Print(int *a,int n){
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\\n",a[n]);
}
int n;
const double eps=1e-6;
double a[N][N],ans[N];
int Gauss(){ //O(n^3)
int r=1;
rep(i,1,n){
int mx=r;
rep(j,r+1,n){
if(fabs(a[j][i])>fabs(a[mx][i])) mx=j;
}
if(fabs(a[mx][i])<eps) continue;
if(mx!=r) swap(a[mx],a[r]);
double x=a[r][i];
rep(j,i,以上是关于高斯消元法的主要内容,如果未能解决你的问题,请参考以下文章