Note - 高斯消元法(證明略)

子洢發表於2024-08-16

線性代數

高斯消元法求解線性方程組

高斯消元法是求解線性方程組的經典演算法,還可以用於行列式計算、求矩陣的逆。

部分程式碼 From「SDOI2006」線性方程組

double a[N][N];//a[i][j] 表示第 i 個方程中第 j 個元的係數,a[i][n+1] 為等號右側的常數項
void Gauss(){
    for(int i=1;i<=n;i++){
        //當前消第 i 個元
        //找第 i 個元係數絕對值最大的行 m
        int mxo=i;
        for(int j=1;j<=n;j++){
            if(fabs(a[j][j])>eps&&j<i)continue;
            if(fabs(a[j][i])>fabs(a[mxo][i]))mxo=j;
        }
        //換第 i 行和第 m 行,使得交換後第 i 行第 i 個係數最大 
        for(int j=1;j<=n+1;j++)
            swap(a[i][j],a[mxo][j]);
        if(fabs(a[i][i])<eps)continue;//無解或有無數解
        for(int j=1;j<=n;j++){//在每一個方程中消元 
            if(i==j)continue;
            double tmp=a[j][i]/a[i][i];//令 tmp 為當前行第 i 個元係數與第 i 行第 i 個元係數的比值
            for(int k=i;k<=n+1;k++)//1~i-1 為 0,可以從 i 開始 
                a[j][k]-=a[i][k]*tmp;
        }
    }
}

理論上 n 個方程出現 n 個元的方程組有定解。

若出現係數全 0 且常數項不為 0,則為無解(方程間矛盾)。

若出現係數全 0 且常數項為 0,則有無數解(n 個方程中有等價的)。

否則矩陣變為

\[\left[\begin{array}{c} k_1 & 0 & 0 & 0 & \text{...} & v_1 \\ 0 & k_2 & 0 & 0 & \text{...} & v_2 \\ 0 & 0 & k_3 & 0 & \text{...} & v_3 \\ \text{...} & \text{...} & \text{...} & \text{...} & \text{...} & \text{...} \\ 0 & 0 & 0 & k_n & \text{...} & v_n \end{array} \right] \]

消去係數可得到簡化階梯形矩陣

\[\left[\begin{array}{c} 1 & 0 & 0 & 0 & \text{...} & v_1/k_1 \\ 0 & 1 & 0 & 0 & \text{...} & v_2/k_2 \\ 0 & 0 & 1 & 0 & \text{...} & v_3/k_3 \\ \text{...} & \text{...} & \text{...} & \text{...} & \text{...} & \text{...} \\ 0 & 0 & 0 & 1 & \text{...} & v_n/k_n \end{array} \right] \]

線性基

高斯消元法。

部分程式碼 From 「JLOI2015」裝備購買

#define ld long double
ld a[N][N];
int cnt;//cnt 表示已求出的線性基數量 
for(int i=1;i<=m;i++){//最多買 m 件裝備
    int now=0;//在為求出的方程中找存在第 i 個元且常數項最小的
    for(int j=cnt+1;j<=n;j++){
        if(fabs(a[j][i])>eps&&(now==0||w[j]<w[now]))now=j;
    }
    if(now==0)continue;//可由其它方程表示出(非線性基)
    ++cnt;
    ans+=w[now];
    for(int k=1;k<=m;k++)
        swap(a[now][k],a[cnt][k]);//交換當前第 cnt 行和後面的第 now 行
    swap(w[now],w[cnt]);
    for(int j=1;j<=n;j++){//與高斯消元同
        if(j!=cnt&&fabs(a[j][i])>eps){
            ld t=a[j][i]/a[cnt][i];
            for(int k=i;k<=m;k++)
                a[j][k]-=a[i][k]*t;
        }
    }
}

異或線性基

貪心法一般更實用,如下。

ll base[55],ans;
bool insert(ll x){
    for(int i=50;i>=0;i--)
        if(x>>i&1){
            if(base[i])x^=base[i];
            else{
                base[i]=x;
                return 1;
            }
        }
    return 0;
}

相關文章