概述
高斯消元法(Gaussian elimination)是求解线性方阵组的一种算法,它也可用来求矩阵的秩,以及求可逆方阵的逆矩阵
模板
1.acwing 883.高斯消元解线性方程组
题目入口
代码
#include<bits/stdc++.h>
using namespace std;
const int N=105;
const double eps=1e-8;
double a[N][N];
void out(int n)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n+1;j++)
{
cout<<a[i][j]<<" ";
}
cout<<endl;
}
cout<<endl;
}
void guass(int n)
{
int r,c;
for(r=1,c=1;c<=n;c++)
{
int pos=r;
for(int i=r+1;i<=n;i++)
{
if(fabs(a[pos][c])<fabs(a[i][c])) pos=i;
}
if(fabs(a[pos][c])<eps) continue;
for(int i=c;i<=n+1;i++) swap(a[pos][i],a[r][i]);
for(int i=n+1;i>=c;i--) a[r][i]/=a[r][c];
for(int i=r+1;i<=n;i++)
{
if(fabs(a[i][c])>eps)
{
for(int j=n+1;j>=c;j--)
{
a[i][j]-=a[i][c]*a[r][j];
}
}
}
r++;
}
if(r<=n)
{
for(int i=r;i<=n;i++)
{
if(fabs(a[i][n+1])>eps)
{
cout<<"No solution"<<endl;
return ;
}
}
cout<<"Infinite group solutions"<<endl;
return ;
}
//out(n);
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];
}
}
for(int i=1;i<=n;i++) printf("%.2lf\n",a[i][n+1]);
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n+1;j++)
{
cin>>a[i][j];
}
}
guass(n);
return 0;
}
2.acwing 884.高斯消元解异或线性方程组
题目入口
代码
#include<bits/stdc++.h>
using namespace std;
int n;
const int N=105;
int a[N][N];
void out(int n)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n+1;j++)
{
cout<<a[i][j]<<" ";
}
cout<<endl;
}
cout<<endl;
}
void guass(int n)
{
int c,r;
for(c=1,r=1;c<=n;c++)
{
int pos=r;
for(int i=r;i<=n;i++)
{
if(a[i][c])
{
pos=i;
break;
}
}
if(!a[pos][c]) continue;
for(int i=c;i<=n+1;i++) swap(a[pos][i],a[r][i]);
for(int i=r+1;i<=n;i++)
{
if(a[i][c])
{
for(int j=n+1;j>=c;j--)
{
a[i][j]^=a[r][j];
}
}
}
r++;
}
//out(n);
if(r<=n)
{
for(int i=r;i<=n;i++)
{
if(a[i][n+1])
{
cout<<"No solution"<<endl;
return ;
}
}
cout<<"Multiple sets of solutions"<<endl;
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];
}
}
for(int i=1;i<=n;i++) cout<<a[i][n+1]<<endl;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n+1;j++)
cin>>a[i][j];
guass(n);
return 0;
}
经典例题
洛谷P3389 高斯消元法
题目描述
给定一个线性方程组,对其求解
输入格式
第一行一个正整数n
第二至n+1行,每行n+1个整数,为a1,a2……和b,代表一组方程
输出格式
共n行,每行一个数,第i行为xi(保留2位小数)
如果不存在唯一解,在第一行输出“No Solution”.
输入样例
3
1 3 4 5
1 4 7 3
9 3 2 2
输出样例
-0.97
5.18
-2.39
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=105;
double mp[N][N];
int n;
signed main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n+1;j++)
{
cin>>mp[i][j];
}
}
for(int i=1;i<=n;i++)//列主元
{
double maxx=mp[i][i];//寻找一列中最大的元素,将此行放在最前面,防止主对角线为mp[i][i]为0
int pos=i;
for(int j=i+1;j<=n;j++)
{
if(mp[j][i]>maxx)
{
pos=j;
maxx=mp[j][i];
}
}
if(pos!=i)
{
for(int j=i;j<=n+1;j++)
{
double k=mp[pos][j];
mp[pos][j]=mp[i][j];
mp[i][j]=k;
}
}
for(int j=i+1;j<=n;j++)//将第i列的元素置0
{
double tmp=1.0*mp[j][i]/mp[i][i];
for(int k=i;k<=n+1;k++)
{
mp[j][k]-=tmp*mp[i][k];
}
}
}
bool flag=true;
for(int i=n;i>=1;i--)
{
for(int j=i+1;j<=n;j++)
{
mp[i][n+1]-=mp[i][j]*mp[j][n+1];//mp[j][n+1]存储的是xj的值
}
if(mp[i][i]==0)//当主对角线有元素为0时无解
{
cout<<"No Solution"<<endl;
flag=false;
break;
}
mp[i][n+1]/=mp[i][i];//主对角线不一定为1,将结果进行处理
}
if(flag)
for(int i=1;i<=n;i++)
{
printf("%.2lf\n",mp[i][n+1]);
}
return 0;
}
洛谷P2455 线性方程组
题目描述
已知n元线性方程组,求解方程组
输入格式
第一行输入未知数个数n
接下来n行,每行n+1个整数,表示每一个方程的系数及方程右边的值
输出格式
如果有唯一解,则输出解,保留两位小数
无解输出-1
无穷多解输出0
输入样例
3
2 -1 1 1
4 1 -1 5
1 1 1 0
输出样例
x1=1.00
x2=0.00
x3=-1.00
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const double eps=1e-8;
int n;
const int N=55;
double mp[N][N];
bool flag=true;
void Gauss(double mp[][N])
{
for(int i=1;i<=n;i++)
{
double maxx=mp[i][i];
int pos=i;
for(int j=i+1;j<=n;j++)
{
if(mp[j][i]-maxx>eps)
{
maxx=mp[j][i];
pos=j;
}
}
if(fabs(maxx)<=eps) continue;//若最大值为0,说明mp[i][i]整列为0,进入下一列
if(pos!=i) for(int j=i;j<=n+1;j++) swap(mp[pos][j],mp[i][j]);
for(int j=i+1;j<=n;j++)
{
if(fabs(mp[j][i])<=eps) continue;
double tmp=mp[j][i]/mp[i][i];
for(int k=i;k<=n+1;k++)
{
mp[j][k]-=tmp*mp[i][k];
}
}
}
for(int i=1;i<=n;i++)//判断0,0,0,0……x 的情况
{
if(fabs(mp[i][n+1])>eps)
{
bool check0=false;
for(int j=1;j<=n;j++) if(fabs(mp[i][j])>eps)
{
check0=true;
break;
}
if(!check0)
{
flag=false;
cout<<"-1"<<endl;
return ;
}
}
}
flag=true;
for(int i=n;i>=1;i--)
{
for(int j=i+1;j<=n;j++)
{
mp[i][n+1]-=mp[i][j]*mp[j][n+1];
}
if(fabs(mp[i][i])<=eps&&fabs(mp[i][n+1])>eps){cout<<"-1"<<endl; flag=false; return ;};//首先判断无解,再判断无穷多解
if(fabs(mp[i][i]<=eps&&fabs(mp[i][n+1])<=eps)) {cout<<"0"<<endl; flag=false; return ;}
mp[i][n+1]/=mp[i][i];
}
}
signed main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n+1;j++)
{
cin>>mp[i][j];
}
}
Gauss(mp);
if(flag)
for(int i=1;i<=n;i++) printf("x%d=%.2lf\n",i,mp[i][n+1]+eps);
return 0;
}