元のリンク(アムウェイを強く推奨)
0.前提知識
- 3 つの変数で連立一次方程式を解く方法を理解する
- 手もあれば頭脳もある
1.回答の表示と保管
まず連立方程式を解きます。
2x+3y+5z=31
x-4y -z=-6
4x+2y-5z=9
この方程式系を、機械が読み取れるテーブル形式に書き込みます。
2 3 5 31
1 -4 -1 -6
4 2 -5 9
最初の列はxxを表しますxの係数、2 列目はyyyの係数...追加の 4 列目は、答えの特定の値であることに
注意してください。最初の行は式 1 を表し、2 列目は式 2 を表します...
常にx、y、zx、y、zを使用するため× 、よ、zはnnを意味します数値nは不便なので、a 1 、 a 2 . . . a_1,a_2...a_n をある1、ある2。。。あるん表現します。
つまり、上の表の意味は次のとおりです。
第i ( 1 ≤ i ≤ n ) i(1\le i\le n)私( 1≤私≤列n ) は各式のai a_iある私はn + 1の係数n+1n+列1は、各式の特定の値。(保存時は通常の値であるため、閲覧者は明確に区別する必要があります)
第i ( 1 ≤ i ≤ n ) i(1\le i\le n)私( 1≤私≤行n )はii 番目を表します私は数式。
次に、テキスト全体で、[ i ] [ j ] a[i][j]を使用します。a[i][j] 表示第 i i 行i、 jj列jの値/係数。
2. ガウス消去法の考え方
名前はとても高級ですが、やり方は非常に雑です。具体的な演算は、加算、減算、消去 + 置換、消去です。
まず、上記の係数行列に従います。
2 3 5 31
1 -4 -1 -6
4 2 -5 9
次に、ガウス消去法を開始します。
列挙ii _i、未知のものを順番に削除します ai a_iある私は。
次にjjを列挙しますj、0 0ではない最小絶対値0のa [ j ] [ i ] a[j][i]a [ j ] [ i ]。
最小値a[j][i]a[j][i]を見つける[ j ] [ i ]のjj _jの後に jj番目を追加しますj式とii表情交換
列挙型jjj,设mul = a [ i ] [ i ] / a [ j ] [ i ] mul=a[i][i]/a[j][i]ムル_ _=a [ i ] [ i ] / a [ j ] [ i ],
将jjj式にmul mulマルとマイナスii _私は式
なぜこれをレイヤーごとに行うのかを分析してみましょう。
まず、iiを列挙します。i、 ii を削除する番号がわかりません。
次に、jjj 使得 a [ j ] [ i ] a[j][i] a [ j ] [ i ]が最小ですが、実際には必要ありません(理由は後で説明します)。交換jjjの式とii私は式です。
後で、各jjj、jjj 式子乘上 a [ i ] [ i ] / a [ j ] [ i ] a[i][i]/a[j][i] a [ i ] [ i ] / a [ j ] [ i ]、 jj は次のようにする必要があるj式ii項iの係数はiiに調整されますi 式子第 i i i項の係数は同じです。jjを
変更しますjマイナスii式iの目的は、 ii を消去する項目iの係数。
0 0ではなく最小の絶対値を選択する理由0の a [ j ] [ i ] a[j][i][ j ] [ i ]のjj _jはどこですか?なぜなら、絶対値が最小の[ j ] [ i ] a[j][i]a [ j ] [ i ] は 、より分割可能な状況を大まかに形成ため、精度の低下を避けることができます。0 0は取れません
0は当然です。
それでも理解できない場合は? 次に、レイヤーごとにシミュレーションします。
この方程式系を例として見てみましょう。
2 3 5 31
1 -4 -1 -6
4 2 -5 9
まず、最初の係数を削除します。
1 -4 -1 -6
2 3 5 31
4 2 -5 9
最小値を求めますa [ 1 ] a[1]式a [ 1 ]については、最初の式に合わせて調整します。
1 -4 -1 -6
1 3/2 5/2 31/2
4 2 -5 9
2 番目の柿× 0.5 \times 0.5× 0 。5。
1 -4 -1 -6
0 11/2 7/2 43/2
4 2 -5 9
2 番目の式から最初の式を減算します。
類推すると、最終的な答えの係数行列は次のようになります: (整列しておらず、少し見苦しい)
4 0 0 20
0 -4.5 0 -9
0 0 7.611 22.833
そして最後のn + 1 n+1n+1係数をiii 行第 i i 列iの値で
3. 見たいコード。
P3389 [テンプレート] ガウス消去法
コメントは少し少ないですが、理解できます。
#include<bits/stdc++.h>
#define RI register int
using namespace std;typedef long long LL;const int inf=1073741823;int FL,CH;template<typename T>void in(T&a){
for(a=0,FL=1,CH=getchar();!isdigit(CH);CH=getchar())FL=(CH=='-')?-1:1;for(;isdigit(CH);CH=getchar())a=a*10+CH-'0';a*=FL;}template<typename T,typename ...Args>void in(T&a,Args&...args){
in(a);in(args...);}
const int maxn=110;const double eps=1e-6;
double a[maxn][maxn];
int n;
int main()
{
cin>>n;
for(RI i=1;i<=n;++i){
for(RI j=1;j<=n+1;++j)scanf("%lf",&a[i][j]);}
//输入系数矩阵
for(RI rp,i=1;i<=n;++i)
{
rp=i;
for(RI j=i+1;j<=n;++j)
if(fabs(a[j][i])>fabs(a[rp][i]))rp=j;
if(fabs(a[rp][i])<=eps)
return printf("No Solution"),0;
//寻找绝对值最小的 j
//这个特殊一点,要判无解
if(i!=rp)swap(a[rp],a[i]);
//交换 j 和 i
double div=a[i][i];
for(RI j=1;j<=n;++j)
if(j!=i){
div=a[j][i]/a[i][i];
//计算 mul 值
for(RI k=1;k<=n+1;++k)
a[j][k]-=a[i][k]*div;
//乘上,再减去
//高斯消元算法的精髓
}
}
for(RI i=1;i<=n;++i)
printf("%.2lf\n",a[i][n+1]/a[i][i]);//回代,并输出答案
return 0;
}