解線性方程組
高斯消元
我們想想人類是如何解線性方程組的,一個例子
\[\begin{cases} x+y+z=1\cdots(1)\\ x+2y+3z=2\cdots(2)\\ x+2y+2z=3\cdots(3) \end{cases} \]
運用小學數學知識,(2)-(3)就可以解出\(\,z\,\),(1)-(3)就可以解出\(\,y+z\,\),依次帶回即可解出所以未知數
考慮模擬此過程,我們先將方程組抽象為矩陣,每一位表示方程中一個未知數在某個方程中的系數(我們認為常數項也是一個\(x^0\)的系數)
那么我們只需要使得這個矩陣滿足\(\forall i>j , a_{i,j}=0\),即上三角形式
考慮矩陣基本變換:
1.交換行或列
2.行列帶系數作差
於是我們只需要每次選定一個元,將矩陣中在它下方同一行系數全部變為0即可
考慮邊界情況
一行全為0,無數解
一行常數項不為0,其他全為0,無解
讀者自證不難
高斯約旦消元
考慮高斯消元回帶不好寫,精度也不高,我們消元時直接消成對角形式,就是每行每列都只有一個值不為0
Talk is cheap , show you the code
read_(n);
for(int i(1);i<=n;++i)
for(int j(1);j<=n+1;++j)
cin>>(x[i][j]);
int pl;
double c;
for(int i(pl=1);i<=n;pl=++i)
{
while(x[pl][i]==0.0&&pl<=n) ++pl;
if(pl==n+1) cout<<"No Solution",exit(0);
if(pl!=i) for(int j(i);j<=n+1;++j) swap(x[i][j],x[pl][j]);
c=x[i][i];
for(int j(i);j<=n+1;++j) x[i][j]/=c;
for(int j(i+1);j<=n;++j)
if(x[j][i]!=0.0)
for(int k(n+1);k>=i;--k)
x[j][k]-=x[j][i]*x[i][k];
}
for(int i(n);i>1;--i)
for(int j(i-1);j;--j)
if(x[j][i]!=0.0)
x[j][n+1]-=x[i][n+1]*x[j][i],x[j][i]=0.0;
for(int i(1);i<=n;++i)
printf("%.2f\n",x[i][n+1]);
復雜度\(\,\Theta(n^3)\,\),看代碼容易發現