高斯消元入门
前言
學高斯消元之前,我覺得這東西真難。學完之后,我發現高斯消元其實也挺簡單的。
先通過一個例子來初步認識高斯消元
這里有一組方程:
\[\begin{cases}5x+4y=24,\\4x+3y=19.\end{cases}\]
這組方程怎么用高斯消元來求解呢?
我們先用一個\(delta\)來記錄要想與②式相加消掉\(x\),①式所要擴大的倍數。不難發現,在這個例子中,\(delta=-\frac45\),因此,我們將①式左右兩邊同乘\(delta\),得:
\[-4x-\frac{16}5y=-\frac{96}5\tag{等式性質}\]
將②式加上③式,可消掉\(x\)得
\[-\frac15y=-\frac15\tag{加減消元法}\]
結合①式和消元得到的④式,我們就得到了:
\[\begin{cases}5x+4y=24,\\-\frac15y=-\frac15\end{cases}\]
然后,我們就可以從最后一個式子開始,求出每一個未知數的答案:
- ④式:
\(y=-\frac15÷-\frac15=1\)
代入①式得
\[5x=20\tag{代入消元法}\] - ①式:
\(x=20÷5=4\)
綜上所述,原方程組的解為
\[ \begin{cases} x=4,\\ y=1. \end{cases} \]
整理思路
接下來,我們整理一下剛才的步驟與思路:
- 第一步:先選擇第一行的第一個元素,然后通過加減消元法消去每一行的這一個元素。
- 第二步:我們發現最后一個方程已經可以直接求解,然后用代入消元法將最后一個方程求出來的解代入前面的每一個方程實現消元。
上面的步驟只是對于二元方程的,對于一個\(n\)元方程應該這樣用高斯消元法:
再接下來就是代碼的實現了。
代碼
#include<bits/stdc++.h> #define max(x,y) ((x)>(y)?(x):(y)) #define min(x,y) ((x)<(y)?(x):(y)) #define abs(x) ((x)<0?-(x):(x)) #define LL long long #define ull unsigned long long #define tc() (A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++) #define N 100 char ff[100000],*A=ff,*B=ff; using namespace std; const double eps=1e-6; int n; double a[N+5][N+5],s[N+5]; inline int read() {int x=0,f=1;static char ch;while(!isdigit(ch=tc())) f=ch^'-'?1:-1;while(x=(x<<3)+(x<<1)+ch-48,isdigit(ch=tc()));return x*f; } inline void swap(double &x,double &y) {double t=x;x=y,y=t; } inline void Find_line(int x)//找到一個行數大于等于x且第x個元素系數不為0的方程,將其移至第x行 {register int i=x,j;while(i<=n&&fabs(a[i][x])<eps) ++i;//只要i不大于n且這一行第x個元素為0,就將i加1if(i>n) puts("No Solution"),exit(0);//如果無解,輸出"No Solution",并退出程序for(j=1;j<=n;++j) swap(a[x][j],a[i][j]);//將第i行移至第x行 } int main() {register int i,j,k;for(n=read(),i=1;i<=n;s[i++]=read()) for(j=1;j<=n;++j) a[i][j]=read();//讀入每一個元素的系數以及等于號右邊的值for(i=1;i<=n;++i) {Find_line(i);for(j=i+1;j<=n;++j)//消去[i+1~n]中每一行第i個元素{double delta=-a[j][i]/a[i][i];//delta記錄在將想要將第i行與第j行相加消掉第i個元素第i行所要擴大的倍數for(k=i;k<=n;++k) a[j][k]+=a[i][k]*delta;//將第j行每一個元素的系數分別加上第i行對應的元素的系數乘以delta后的值s[j]+=s[i]*delta;}}for(i=n;i;--i) {if(!a[i][i]) return puts("No Solution"),0;//如果第i行第i個元素的系數為0,就輸出"No Solution",并退出程序for(s[i]/=a[i][i],j=i-1;j;--j) s[j]-=a[j][i]*s[i];//計算出第i個未知數的值,并將第i個元素的值代入第1~i-1行的式子中消去第i個未知數}for(i=1;i<=n;++i) printf("%.2lf\n",s[i]);//輸出每一個未知數的值return 0; }例題
一道例題:【BZOJ1013】[JSOI2008] 球形空間產生器
轉載于:https://www.cnblogs.com/chenxiaoran666/p/Gauss.html
總結
- 上一篇: 大整数乘除法
- 下一篇: 脱壳实践之手动构造输入表