線性代數
高斯消元法求解線性方程組
高斯消元法是求解線性方程組的經典演算法,還可以用於行列式計算、求矩陣的逆。
部分程式碼 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;
}