高斯消元
是个求解线性一元多次方程的好办法
eg:
像这个样子 把方程列成一个矩阵 矩阵的前n个元素是系数 第n+1个存的是这一个方程的答案
如 2x+3y+z=5 那么 矩阵的这一行就是 2 3 1 5
每次消掉一列使这一列的元素 为0
除了矩阵的第[i][i]个为1 最后 第 i 行的第n+1个的值 就是方程第 i 个元素的解
注意两种情况:
1.这一列都为0除了n+1这个位子上不为0 这就相当于 0x+0y+0z=n(n!=0)
那么根据小学的知识 这个方程是无解的
2.这一行每一个都为0 类似0x+0y+0z=0
(因为x是第i行i个)那么无论x取何值 这个方程都有解 那么这个x就是自由元(又叫自由变元)
此x取何值 可能会对y和z产生影响 但方程会有解(多组)
PS:
高斯消元有两种方法:
一种是消完左下的小三角 然后从最后一个网上回带这个做法比较标准 也比较对 但是多了一步
我更喜欢的是另一种 叫
高斯-若尔当消元法(Gauss-Jordan Elimination)
此做法不只是消下面的小三角 一次把一列都消掉 那么最后就不用回带 好写一点虽然听说这个方法效率比那个低 实际上我觉得差不了多少 毕竟这个好打一点点(不用回带)
模板:洛谷的3389
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define eps 0.00000001
using namespace std;
double a[1000][1000];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n+1;j++)
scanf("%lf",&a[i][j]);
for(int i=1;i<=n;i++){
int k=i;
for(int j=i+1;j<=n;j++)
if(fabs(a[i][j])<fabs(a[k][j]))k=j;//找最大的 移到第i行(当前要求的行)去
if(fabs(a[k][i])<eps){//无解的情况 最大的是0 记得加fabs 考虑浮点误差
printf("No Solution\n");
return 0;
}
if(k!=i){
for(int j=1;j<=n+1;j++)//往第i行交换 记得是到n+1 因为答案也要算
swap(a[k][j],a[i][j]);
}
double tmp=a[i][i];
for(int j=i;j<=n+1;j++)
a[i][j]/=tmp;//a[i][i]系数化为1
for(int p=1;p<=n;p++)
{
if(p!=i)
{
double t=a[p][i];
for(int j=i;j<=n+1;j++)
a[p][j]=a[p][j]-t*a[i][j];//消元
}
}
}
for(int i=1;i<=n;i++)
printf("%.2f\n",a[i][n+1]);
return 0;
}