洛谷P3389 【模板】高斯消元法
题目背景
Gauss消元
题目描述
给定一个线性方程组,对其求解
输入输出格式
输入格式:
第一行,一个正整数 nn
第二至 n+1n+1行,每行 n+1n+1 个整数,为 a_1, a_2 \cdots a_na
1
,a
2
⋯a
n
和 bb,代表一组方程。
输出格式:
共n行,每行一个数,第 ii行为 x_ix
i
(保留2位小数)
如果不存在唯一解,在第一行输出”No Solution”.
输入输出样例
输入样例#1:
3
1 3 4 5
1 4 7 3
9 3 2 2
输出样例#1:
-0.97
5.18
-2.39
说明
1 \leq n \leq 100, \left | a_i \right| \leq {10}^4 , \left |b \right| \leq {10}^4 1≤n≤100,∣a
i
∣≤10
4
,∣b∣≤10
4
【题解】:
高斯消元法,数学中比较常见的方法。
通过构造矩阵来求解多元一次方程,其主要思想就是加减消元法。
主要步骤如下(构成上三角):
1.选定未被选择过的、xi项系数绝对值最大的一行(这样更加容易判断是否有解),将整个式子除以xi的系数(xi系数化为1)。同时将其交换至第i行(方便求解)
2.将未被选择过的行中的该项全部按照系数相应的减去选定的那行的系数(剩下的其他行xi系数化为0)
当所有行都选定过时,已经构成了上三角
3.倒序求解,每次将常数减去已经求出的所有项的解,此时可以求出当前项的解(将已知解带入求未知解)
最后依次输出即可
代码如下:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAX 110
using namespace std;
double g[MAX][MAX];
int n,now;
inline void read(double &x)
{
x=0;
short int t=1;
char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')
{
t=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=x*10+ch-48;
ch=getchar();
}
x*=t;
}
int main()
{
cin>>n;
for(int i=1;i<=n;++i)
for(int j=1;j<=n+1;++j)
read(g[i][j]);
for(int i=1;i<=n;++i)
{
now=i;
for(int j=i+1;j<=n;++j)//找出当前项系数的绝对值的最大值
if(fabs(g[now][i])<fabs(g[j][i]))
now=j;
for(int j=i;j<=n+1;++j)//将其放在对应的行,方便计算
swap(g[now][j],g[i][j]);
if(g[i][i]==0)//如果此时绝对值最大系数已经为0
{ //则证明此方程组无解
cout<<"No Solution"<<endl;
return 0;
}
for(int j=i+1;j<=n+1;++j)//将系数化为1
g[i][j]/=g[i][i];
g[i][i]=1;
for(int j=i+1;j<=n;++j)//在其他式子中将此项系数化为0
{
for(int k=i+1;k<=n+1;++k)
g[j][k]-=g[j][i]*g[i][k];
g[j][i]=0;
}
}//做完之后,剩余的矩阵是上三角
for(int i=n;i>=1;--i)//倒着求解即可
{
for(int j=i+1;j<=n;++j)//减去后面所有已经求出解的值
{
g[i][n+1]-=g[i][j]*g[j][n+1];
g[i][j]=0;
}
g[i][n+1]/=g[i][i]; //只剩下当前的未知量以及常数量(其实没必要除,因为已经是1了)
g[i][i]=1;
}
for(int i=1;i<=n;++i)
printf("%.2f\n",g[i][n+1]);
return 0;
}