高斯 約旦消元法

2022-10-08 20:00:21 字數 3660 閱讀 9571

學了將近兩個晚上。突然看懂時感覺自己是個**。

寫個部落格記一下吧。

模板:洛谷p3389 【模板】高斯消元法

有 \(n\) 個形如 \(a_1x_1+a_2x_2+\cdots+a_nx_n=b\) 的方程。解方程組。

有唯一解則將其求出,否則輸出no solution

把方程組用矩陣形式寫出來

\[\left( \begin

a_ & a_ & \cdots & a_ \\

a_ & a_ & \cdots & a_ \\

\vdots & \vdots & \ddots & \vdots \\

a_ & a_ & \cdots & a_

\end \middle| \begin

b_1 \\ b_2 \\ \vdots \\ b_n

\end \right)\]

(這個東西叫增廣矩陣)

考慮選 \(x_1\) 為主元。

若所有方程中 \(x_1\) 的係數均為 0,則 \(x_1\) 是個自由未知量,方程組無唯一解。直接結束即可。

否則,選出 \(|a_|\) 最大的第 \(i\) 行(這樣精度誤差最小,雖然我也不知道為什麼)

然後用第 \(i\) 個方程和其它所有方程做一遍加減消元,消去 \(x_1\)。

不妨設 \(i=1\),則得到新的增廣矩陣大概是下面這樣

\[\left( \begin

1 & 1 & 1 & \cdots & 1 \\

0 & 1 & 1 & \cdots & 1 \\

0 & 1 & 1 & \cdots & 1 \\

\vdots & \vdots & \vdots & \ddots & \vdots \\

0 & 1 & 1 & \cdots & 1

\end \middle| \begin

1 \\ 1 \\ 1 \\ \vdots \\ 1

\end \right)\]

0 表示該項已被消去,1 表示其它。

對 \(x_2\) 執行相同操作。注意之前選過的行不能再選。

設這次選了第 \(j(j\ne i)\) 行,以 \(j=2\) 為例,新的增廣矩陣是

\[\left( \begin

1 & 0 & 1 & \cdots & 1 \\

0 & 1 & 1 & \cdots & 1 \\

0 & 0 & 1 & \cdots & 1 \\

\vdots & \vdots & \vdots & \ddots & \vdots \\

0 & 0 & 1 & \cdots & 1

\end \middle| \begin

1 \\ 1 \\ 1 \\ \vdots \\ 1

\end \right)\]

重複上述過程,最終得到

\[\left( \begin

1 & 0 & 0 & \cdots & 0 \\

0 & 1 & 0 & \cdots & 0 \\

0 & 0 & 1 & \cdots & 0 \\

\vdots & \vdots & \vdots & \ddots & \vdots \\

0 & 0 & 0 & \cdots & 1

\end \middle| \begin

1 \\ 1 \\ 1 \\ \vdots \\ 1

\end \right)\]

到這裡就算是解完了。

#include#include#define mcpy(a,b) memcpy(a,b,sizeof ta)

const int n=110; int n; double ta[n],a[n][n];

inline double abs(double x)

int main()

}for (int i=1; i<=n; ++i)

printf("%.2lf\n",a[i][n+1]/a[i][i]);

return 0;

}

時間複雜度 \(o(n^3)\)。

另一道模板題:洛谷p2455 [sdoi2006]線性方程組

這次需要區分無解和有無陣列解。

其實也很簡單

正常做消元,如果遇到某一列係數全為 0,就直接擺爛(反正也消不出啥東西),直接跳到下一列

這樣得到的增廣矩陣依然是

\[\left( \begin

1 & 0 & 0 & \cdots & 0 \\

0 & 1 & 0 & \cdots & 0 \\

0 & 0 & 1 & \cdots & 0 \\

\vdots & \vdots & \vdots & \ddots & \vdots \\

0 & 0 & 0 & \cdots & 1

\end \middle| \begin

1 \\ 1 \\ 1 \\ \vdots \\ 1

\end \right)\]

但這次寫著 1 的位置可能會出現 0。

首先檢查一下有沒有 \(0x\ne 0\) 這樣的方程出現。有則說明無解。

否則再檢查有沒有 \(0x=0\) 這樣的方程出現。有則說明有無陣列解。

否則說明有唯一解。

然後我們獲得了 80pts 的好成績。

看一眼報錯資訊,第三個點無窮解判成無解了,第八個點好像把0.00輸出成了-0.00

後者是詭異的 feature,輸出時加上乙個很小的數即可解決。

前者更加離譜,我 debug 了一晚上也沒找到錯。

三天後我終於在題解區翻到一組 hack 資料:

2

0 2 3

0 0 0

答案為0,而程式會輸出-1

因為第一次消元時選了第一行,然後第二行沒法消了,但原本是可以消的。所以寄了。

原因是消元時只是貪心地選擇了當前列係數最大的一行。沒有考慮到對後面造成的影響。

補救措施:微調一下選擇行的方案,如果兩行的係數絕對值相等,選後面的數更小的。

#include#include#define mcpy(a,b) memcpy(a,b,sizeof ta)

#define rep(i,l,r) for (int i=l; i<=r; ++i)

const int n=52; const double eps=1e-6;

int n,f1,f2; double ta[n],a[n][n];

inline double abs(double x)

inline int f(double x)

bool cmp(int i,int j,int k,bool f)

int main()

}rep(i,1,n) f(a[i][i])||(f1=1,f(a[i][n+1])&&(f2=1));

if (f1) return puts(f2?"-1":"0"),0;

rep(i,1,n) printf("x%d=%.2lf\n",i,a[i][n+1]/a[i][i]+eps);

return 0;

}

做完之後還是感覺這**醜的一批。

不過反正能過,複雜度也沒假,就這樣吧(

高斯 約旦消元法

高斯 約旦消元法 此演算法是基於高斯消元的基礎上改進而成的,唯一不同之處是多進行了幾次矩陣變換使得化為行最簡型矩陣。相比於高斯消元法此方法效率較低,但是不需要回帶求解 此演算法的過程大概為 首先確定每個a i i a i i a i i 不為0 00 如果為0 00就和下面的行替換 接著將每個a i...

數學 高斯 約旦消元法

給定 n 元一次方程組 begin a x 1 a x 2 cdots a x n b 1 a x 1 a x 2 cdots a x n b 2 cdots a x 1 a x 2 cdots a x n b n end 請求出方程組的解的情況 對於這樣的問題,我們可以使用高斯消元法進行求解,當然...

高斯 約旦消元法 理解

高斯消元是一種解方程的很巧妙的方法,核心是把方程轉換成矩陣形式,然後再通過加減消元,求出值後再回帶,就解出了這個方程,這裡我就不贅述了。我一般用高斯 約旦消元法,這種方法是直接轉換成單位矩陣求解,減少回帶次數,提高精確度,實現方式如下 下方是乙個方程 把它轉換成矩陣形式就是 我們可以這樣對其進行變換...