1. 程式人生 > >P3389 【模板】高斯消元法

P3389 【模板】高斯消元法

高斯消元 方程 clu wap n) cpp 移動 urn tdi

刷模板多好啊,不用動腦。。。


新學習了高斯消元。

其實高斯消元就是把我們小學就學過的解方程組用程序語言表達出來了而已。

小學學的東西有加減法,代入法。我們這裏都會用到。

但是也挺難記的

給你三個形如ax+by+cz=d,怎麽求出答案?n個呢?

所以還是老老實實地學習一下高斯消元。

首先,我們程序只能記錄下一條方程的系數,用二維數組存下來。不然教我自變量怎麽存

我們程序分為\(n\)個循環,因為我們共有\(n\)個未知數和方程。

根據我的理解,第\(i\)個循環是化簡第\(i\)個方程式,使之只含有\(n - i + 1\)個未知數。

每一次循環,我們最重要的一個數字是\(a[i][i]\)!因為我們的目標是把它化為1。

在正事之前,先做一個優化:將第\(i\)項系數最大的方程移動到第\(i\)行。聽別人說可以減小誤差。

接下來要做的事情是:將這個第\(i\)行的第\(i\)個系數化為1。

做法也非常簡單,不過註意一下:最終得到的矩陣,第\(i\)行的前\(i - 1\)個變量的系數都為0!這樣的操作支持回帶。

所以從第\(i\)位到\(n+1\)位同除以a[i][i]。這樣就可以把第\(i\)個系數化為1。

然後求出這麽一個方程,就可以為下面方程的化簡做鋪墊。

我們可以約掉這個方程下面那個方程的第\(i\)位系數。如何操作?

很簡單。只需要記憶一個div為第\(i+1\)個方程的第\(i\)個系數,然後第\(i\)

個方程左右同乘以div,得到的第\(i\)位系數會與第\(i+1\)位的一致,運用加減法,減掉就可以了。

最終求出來的矩陣,因為每一次運用加減法可以消掉一個變量,所以最終長成這樣:

1.00 0.33 0.22 0.22 
0.00 1.00 1.85 0.76 
0.00 0.00 1.00 -2.39 

很容易就能發現最後一個x的值就是-2.39是吧。

所以我們可以從下往上回帶,每一次回帶就能求出一個x的值。

具體操作也很簡單,等式兩邊同時減掉(系數\(\times\)變量值),用循環實現。

好的,終於講完了。

今晚要試試,重新打一下。

在此對@皎月半灑花 表示忠心的感謝。我永遠喜歡花姐姐

花姐姐不會看到我這個蒟蒻的博客,所以放心的寫。。。

忘記貼代碼了,我貼:

#include<cstdio>
#include<cmath>
#include<algorithm>
const int maxn = 115;
const double eps = 1e-7;
double a[maxn][maxn];
double ans[maxn];
int n;
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n + 1; j++)
        {
            scanf("%lf", &a[i][j]);
        }
    }
    for(int i = 1; i <= n; i++)
    {
        int r = i;
        for(int j = i + 1; j <= n; j++)
        {
            if(fabs(a[j][i]) > fabs(a[r][i])) r = j;
        }
        if(fabs(a[r][i]) < eps)
        {
            printf("no solution\n");
            return 0;
        }
        if(r != i) std::swap(a[r], a[i]);
        double div = a[i][i];
        for(int j = i; j <= n + 1; j++) a[i][j] /= div;
        for(int j = i + 1; j <= n; j++)
        {
            div = a[j][i];
            for(int k = i; k <= n + 1; k++)
            {
                a[j][k] -= a[i][k] * div;//pay attention to here
            }
        }
    }
    ans[n] = a[n][n + 1];
    for(int i = n - 1; i >= 1; i--)
    {
        ans[i] = a[i][n + 1];
        for(int j = i + 1; j <= n; j++)
        {
            ans[i] -= ans[j] * a[i][j];
        }
    }
    for(int i = 1; i <= n; i++) printf("%.2lf\n", ans[i]);
    return 0;
}

P3389 【模板】高斯消元法