高斯消元 模版
高斯消元法,是線性代數中的一個算法,可用來求解線性方程組,并可以求出矩陣的秩,以及求出可逆方陣的逆矩陣。
高斯消元法的原理是:
若用初等行變換將增廣矩陣 化為 ,則AX = B與CX = D是同解方程組。
所以我們可以用初等行變換把增廣矩陣轉換為行階梯陣,然后回代求出方程的解。
以上是線性代數課的回顧,下面來說說高斯消元法在編程中的應用。
首先,先介紹程序中高斯消元法的步驟:
(我們設方程組中方程的個數為equ,變元的個數為var,注意:一般情況下是n個方程,n個變元,但是有些題目就故意讓方程數與變元數不同)
1. 把方程組轉換成增廣矩陣。
2. 利用初等行變換來把增廣矩陣轉換成行階梯陣。
枚舉k從0到equ – 1,當前處理的列為col(初始為0) ,每次找第k行以下(包括第k行),col列中元素絕對值最大的列與第k行交換。如果col列中的元素全為0,那么則處理col + 1列,k不變。
3. 轉換為行階梯陣,判斷解的情況。
① 無解
當方程中出現(0, 0, …, 0, a)的形式,且a != 0時,說明是無解的。
② 唯一解
條件是k = equ,即行階梯陣形成了嚴格的上三角陣。利用回代逐一求出解集。
③ 無窮解。
條件是k < equ,即不能形成嚴格的上三角形,自由變元的個數即為equ – k,但有些題目要求判斷哪些變元是不缺定的。
??? 這里單獨介紹下這種解法:
首先,自由變元有var - k個,即不確定的變元至少有var - k個。我們先把所有的變元視為不確定的。在每個方程中判斷不確定變元的個數,如果大于1個,則該方程無法求解。如果只有1個變元,那么該變元即可求出,即為確定變元。
以上介紹的是求解整數線性方程組的求法,復雜度是O(n3)。浮點數線性方程組的求法類似,但是要在判斷是否為0時,加入EPS,以消除精度問題。
下面講解幾道OJ上的高斯消元法求解線性方程組的題目:
POJ 1222 EXTENDED LIGHTS OUT
http://acm.pku.edu.cn/JudgeOnline/problem?id=1222
POJ 1681 Painter's Problem
http://acm.pku.edu.cn/JudgeOnline/problem?id=1681
POJ 1753 Flip Game
http://acm.pku.edu.cn/JudgeOnline/problem?id=1753
POJ 1830 開關問題
http://acm.pku.edu.cn/JudgeOnline/problem?id=1830
POJ 3185 The Water Bowls
http://acm.pku.edu.cn/JudgeOnline/problem?id=3185
開關窗戶,開關燈問題,很典型的求解線性方程組的問題。方程數和變量數均為行數*列數,直接套模板求解即可。但是,當出現無窮解時,需要枚舉解的情況,因為無法判斷哪種解是題目要求最優的。
POJ 2947 Widget Factory
http://acm.pku.edu.cn/JudgeOnline/problem?id=2947
求解同余方程組問題。與一般求解線性方程組的問題類似,只要在求解過程中加入取余即可。
注意:當方程組唯一解時,求解過程中要保證解在[3, 9]之間。
POJ 1166 The Clocks
http://acm.pku.edu.cn/JudgeOnline/problem?id=1166
經典的BFS問題,有各種解法,也可以用逆矩陣進行矩陣相乘。
但是這道題用高斯消元法解決好像有些問題(困擾了我N天...持續困擾中...),由于周期4不是素數,故在求解過程中不能進行取余(因為取余可能導致解 集變大),但最后求解集時,還是需要進行取余操作,那么就不能保證最后求出的解是正確的...在discuss里提問了好幾天也沒人回答...希望哪位路 過的大牛指點下~~
POJ 2065 SETI
http://acm.pku.edu.cn/JudgeOnline/problem?id=2065
同樣是求解同余方程組問題,由于題目中的p是素數,可以直接在求解時取余,套用模板求解即可。(雖然AC的人很少,但它還是比較水的一道題,)
POJ 1487 Single-Player Games
http://acm.pku.edu.cn/JudgeOnline/problem?id=1487
很麻煩的一道題目...題目中的敘述貌似用到了編譯原理中的詞法定義(看了就給人不想做的感覺...)
解方程組的思想還是很好看出來了(前提是通讀題目不下5遍...),但如果把樹的字符串表達式轉換成方程組是個難點,我是用棧 + 遞歸的做法分解的。首先用棧的思想求出該結點的孩子數,然后遞歸分別求解各個孩子。
這題解方程組也與眾不同...首先是求解浮點數方程組,要注意精度問題,然后又詢問不確定的變元,按前面說的方法求解。
一頓折騰后,這題居然寫了6000+B...而且囧的是巨人C++ WA,G++ AC,可能還是精度的問題吧...看這題目,看這代碼,就沒有改的欲望...
hdu OJ 2449
http://acm.hdu.edu.cn/showproblem.php?pid=2449
哈爾濱現場賽的一道純高斯題,當時鶴牛敲了1個多小時...主要就是寫一個分數類,套個高精模板(偷懶點就Java...)搞定~~
注意下0和負數時的輸出即可。
fze OJ 1704
http://acm.fzu.edu.cn/problem.php?pid=1704
福大月賽的一道題目,還是經典的開關問題,但是方程數和變元數不同(考驗模板的時候到了~~),最后要求增廣陣的階,要用到高精度~~
Sgu 275 To xor or not to xor
http://acm.sgu.ru/problem.php?contest=0&problem=275
題解:
http://hi.baidu.com/czyuan_acm/blog/item/be3403d32549633d970a16ee.html
這里提供下自己寫的還算滿意的求解整數線性方程組的模板(浮點數類似,就不提供了)~~
?
??1?#include?<iostream>??2?#include?<string>
??3?#include?<cmath>
??4?using?namespace?std;
??5?
??6?const?int?maxn?=?105;
??7?
??8?int?equ,?var;?//?有equ個方程,var個變元。增廣陣行數為equ,?分別為0到equ?-?1,列數為var?+?1,分別為0到var.
??9?int?a[maxn][maxn];
?10?int?x[maxn];?//?解集.
?11?bool?free_x[maxn];?//?判斷是否是不確定的變元.
?12?int?free_num;
?13?
?14?void?Debug(void)
?15?{
?16?????int?i,?j;
?17?????for?(i?=?0;?i?<?equ;?i++)
?18?????{
?19?????????for?(j?=?0;?j?<?var?+?1;?j++)
?20?????????{
?21?????????????cout?<<?a[i][j]?<<?"?";
?22?????????}
?23?????????cout?<<?endl;
?24?????}
?25?????cout?<<?endl;
?26?}
?27?
?28?inline?int?gcd(int?a,?int?b)
?29?{
?30?????int?t;
?31?????while?(b?!=?0)
?32?????{
?33?????????t?=?b;
?34?????????b?=?a?%?b;
?35?????????a?=?t;
?36?????}
?37?????return?a;
?38?}
?39?
?40?inline?int?lcm(int?a,?int?b)
?41?{
?42?????return?a?*?b?/?gcd(a,?b);
?43?}
?44?
?45?//?高斯消元法解方程組(Gauss-Jordan?elimination).(-2表示有浮點數解,但無整數解,-1表示無解,0表示唯一解,大于0表示無窮解,并返回自由變元的個數)
?46?int?Gauss(void)
?47?{
?48?????int?i,?j,?k;
?49?????int?max_r;?//?當前這列絕對值最大的行.
?50?int?col;?//?當前處理的列.
?51?????int?ta,?tb;
?52?????int?LCM;
?53?????int?temp;
?54?????int?free_x_num;
?55?????int?free_index;
?56?????//?轉換為階梯陣.
?57?????col?=?0;?//?當前處理的列.
?58?????for?(k?=?0;?k?<?equ?&&?col?<?var;?k++,?col++)
?59?????{?//?枚舉當前處理的行.
?60?????????//?找到該col列元素絕對值最大的那行與第k行交換.(為了在除法時減小誤差)
?61?????????max_r?=?k;
?62?????????for?(i?=?k?+?1;?i?<?equ;?i++)
?63?????????{
?64?????????????if?(abs(a[i][col])?>?abs(a[max_r][col]))?max_r?=?i;
?65?????????}
?66?????????if?(max_r?!=?k)
?67?????????{?//?與第k行交換.
?68?????????????for?(j?=?k;?j?<?var?+?1;?j++)?swap(a[k][j],?a[max_r][j]);
?69?????????}
?70?????????if?(a[k][col]?==?0)
?71?????????{?//?說明該col列第k行以下全是0了,則處理當前行的下一列.
?72?????????????k--;?continue;
?73?????????}
?74?????????for?(i?=?k?+?1;?i?<?equ;?i++)
?75?????????{?//?枚舉要刪去的行.
?76?????????????if?(a[i][col]?!=?0)
?77?????{
?78?????????????????LCM?=?lcm(abs(a[i][col]),?abs(a[k][col]));
?79?????????????????ta?=?LCM?/?abs(a[i][col]),?tb?=?LCM?/?abs(a[k][col]);
?80?????????????????if?(a[i][col]?*?a[k][col]?<?0)?tb?=?-tb;?//?異號的情況是兩個數相加.
?81?????????????????for?(j?=?col;?j?<?var?+?1;?j++)
?82?????????????????{
?83?????????????????????a[i][j]?=?a[i][j]?*?ta?-?a[k][j]?*?tb;
?84?????????????????}
?85?????}
?86?????????}
?87?????}
?88???? Debug();//不用加這個
?89?????//?1.?無解的情況:?化簡的增廣陣中存在(0,?0,?...,?a)這樣的行(a?!=?0).
?90?????for?(i?=?k;?i?<?equ;?i++)
?91?????{?//?對于無窮解來說,如果要判斷哪些是自由變元,那么初等行變換中的交換就會影響,則要記錄交換.
?92?????????if?(a[i][col]?!=?0)?return?-1;
?93?????}
?94?????//?2.?無窮解的情況:?在var?*?(var?+?1)的增廣陣中出現(0,?0,?...,?0)這樣的行,即說明沒有形成嚴格的上三角陣.
?95?????//?且出現的行數即為自由變元的個數.
?96?????if?(k?<?var)
?97?????{
?98?????????//?首先,自由變元有var?-?k個,即不確定的變元至少有var?-?k個.
?99?????????for?(i?=?k?-?1;?i?>=?0;?i--)
100?????????{
101?????????????//?第i行一定不會是(0,?0,?...,?0)的情況,因為這樣的行是在第k行到第equ行.
102?????????????//?同樣,第i行一定不會是(0,?0,?...,?a),?a?!=?0的情況,這樣的無解的.
103?????????????free_x_num?=?0;?//?用于判斷該行中的不確定的變元的個數,如果超過1個,則無法求解,它們仍然為不確定的變元.
104?????????????for?(j?=?0;?j?<?var;?j++)
105?????????????{
106?????????????????if?(a[i][j]?!=?0?&&?free_x[j])?free_x_num++,?free_index?=?j;
107?????????????}
108?????????????if?(free_x_num?>?1)?continue;?//?無法求解出確定的變元.
109?????????????//?說明就只有一個不確定的變元free_index,那么可以求解出該變元,且該變元是確定的.
110?????????????temp?=?a[i][var];
111?????????????for?(j?=?0;?j?<?var;?j++)
112?????????????{
113?????????????????if?(a[i][j]?!=?0?&&?j?!=?free_index)?temp?-=?a[i][j]?*?x[j];
114?????????????}
115?????????????x[free_index]?=?temp?/?a[i][free_index];?//?求出該變元.
116?????????????free_x[free_index]?=?0;?//?該變元是確定的.
117?????????}
118?????????return?var?-?k;?//?自由變元有var?-?k個.
119?????}
120?????//?3.?唯一解的情況:?在var?*?(var?+?1)的增廣陣中形成嚴格的上三角陣.
121?????//?計算出Xn-1,?Xn-2?...?X0.
122?????for?(i?=?var?-?1;?i?>=?0;?i--)
123?????{
124?????????temp?=?a[i][var];
125?????????for?(j?=?i?+?1;?j?<?var;?j++)
126?????????{
127?????????????if?(a[i][j]?!=?0)?temp?-=?a[i][j]?*?x[j];
128?????????}
129?????????if?(temp?%?a[i][i]?!=?0)?return?-2;?//?說明有浮點數解,但無整數解.
130?????????x[i]?=?temp?/?a[i][i];
131?????}
132?return?0;
133?}
134?int?main(void)
135?{
136??
137?
138????freopen("Input.txt",?"r",?stdin);
139?????int?i,?j;
140?????while?(scanf("%d?%d",?&equ,?&var)?!=?EOF)
141?????{
142?????????memset(a,?0,?sizeof(a));
143????memset(x,?0,?sizeof(x));
144????memset(free_x,?1,?sizeof(free_x));?//?一開始全是不確定的變元.
145?????????for?(i?=?0;?i?<?equ;?i++)
146?????????{
147?????????????for?(j?=?0;?j?<?var?+?1;?j++)
148?????????????{
149?????????????????scanf("%d",?&a[i][j]);
150?????????????}
151?????????}
152?//????????Debug();
153?????????free_num?=?Gauss();
154?????????if?(free_num?==?-1)?printf("無解!\n");
155????else?if?(free_num?==?-2)?printf("有浮點數解,無整數解!\n");
156?????????else?if?(free_num?>?0)
157?????????{
158?????????????printf("無窮多解!?自由變元個數為%d\n",?free_num);
159?????????????for?(i?=?0;?i?<?var;?i++)
160?????????????{
161?????????????????if?(free_x[i])?printf("x%d?是不確定的\n",?i?+?1);
162?????????????????else?printf("x%d:?%d\n",?i?+?1,?x[i]);
163?????????????}
164?????????}
165?????????else
166?????????{
167?????????????for?(i?=?0;?i?<?var;?i++)
168?????????????{
169?????????????????printf("x%d:?%d\n",?i?+?1,?x[i]);
170?????????????}
171?????????}
172?????????printf("\n");
173?????}
174?????return?0;
175?}
轉載于:https://www.cnblogs.com/acSzz/archive/2012/08/29/2661625.html
總結
- 上一篇: XslTransform.Transfo
- 下一篇: How to check table l