一. 高斯消元求线性方程组
基本思路:
先从上往下消成一个上三角矩阵
再从下往上代入求值
判断解的情况:
1.出现类似0=1形式:无解
2.出现0=0形式:多组解
3.其他情况:一组解
代码:
typedef double db[N][N];
int n;
bool Gauss(db A){
for(int i=1;i<n;i++){
int r=i;
for(int j=i+1;j<=n;j++)
if(fabs(A[j][i]-A[r][i])>eps) r=j; //为保证精度,选取最大的A[r][i]作除数
for(int j=i;j<=n+1;j++) swap(A[i][j],A[r][j]);
if(fabs(A[i][i])<=eps) continue; //可能多解也可能无解
for(int j=i+1;j<=n;j++){
double x=A[j][i]/A[i][i];
for(int k=i;k<=n+1;k++)
A[j][k]-=A[i][k]*x;
}
}
for(int i=n;i>0;i--){
for(int j=n;j>i;j--) A[i][n+1]-=A[i][j]*A[j][n+1];
if(fabs(A[i][i])<=eps) return false; //可能多解也可能无解
A[i][n+1]/=A[i][i];
}
return true;
}
二.矩阵求逆
定义:
对于 (n imes n) 的矩阵 (A) , 若存在矩阵 (B) 满足 (A imes B = E) ((E) 为单位矩阵),则称 (B) 为 (A) 的逆矩阵
性质:
令矩阵 (P=[A|E]) ,对 (P) 进行一些线性变换使之变成 ([E|B]) 的形式,则 (A imes B = E)
证明:
首先有一个可证的性质,对矩阵 (M) 进行线性变换 等价于 (M) 左乘一个矩阵 (N) (证明略)
然后就比较显然了,(A imes B = E,E imes B = B)
做法:
先从上往下将 (P) 的 (A) 部分消成上三角矩阵
再从下往上将 (P) 的 (A) 部分消成单位矩阵
代码:
(对大质数取模版)
#define xzy 1000000007
typedef long long ll;
typedef int Mat[N][N];
int Pow_mod(int x,int y){
int ret=1;
while(y){
if(y&1) ret=((ll)ret*x)%xzy;
x=((ll)x*x)%xzy;
y>>=1;
}
return ret;
}
bool Gauss_inv(Mat A,int n,int m){ // m=2n
for(int i=1;i<=n;i++){
int r=i;
for(int j=i+1;j<=n;j++)
if(A[j][i]>A[r][i]) r=j;
for(int j=i;j<=m;j++) swap(A[i][j],A[r][j]);
if(!A[i][i]) return false;
int y=Pow_mod(A[i][i],xzy-2);
for(int j=i+1;j<=n;j++){
int x=(ll)A[j][i]*y%xzy;
for(int k=i;k<=m;k++)
A[j][k]=(A[j][k]-(ll)A[i][k]*x%xzy+xzy)%xzy;
}
}
for(int i=n;i>0;i--){
for(int j=i+1;j<=n;j++){
for(int k=n+1;k<=m;k++)
A[i][k]=(A[i][k]-(ll)A[i][j]*A[j][k]%xzy+xzy)%xzy;
A[i][j]=0;
}
int x=Pow_mod(A[i][i],xzy-2);
for(int j=n+1;j<=m;j++) A[i][j]=((ll)A[i][j]*x)%xzy;
A[i][i]=1;
}
return true;
}
三.矩阵行列式
定义:
略(会用就行了)
重要性质:
交换行列式的两行,行列式取相反数
将行列式某一行元素乘以同一个数后加到另一行对应的元素上去,行列式不变
上三角矩阵或下三角矩阵行列式为正对角线上元素乘积
代码:
(对合数取模——利用辗转相除法将 (a,b) 中的一个消为0)
#define xzy 1000000000
typedef int Mat[N][N];
typedef long long ll;
int Gauss(Mat A,int n){
int ret=1;
for(int j=1;j<=n;j++){
for(int i=j+1;i<=n;i++)
while(A[i][j]){ // (a,b) -> (b,a%b) = (b,a-(a/b)*b)
int t=A[j][j]/A[i][j]; //A[i][j]相当于b,A[j][j]相当于a
for(int k=j;k<=n;k++){
A[j][k]=(A[j][k]-(ll)A[i][k]*t%xzy+xzy)%xzy;
swap(A[i][k],A[j][k]);
}
ret*=-1;
}
ret=((ll)ret*A[j][j]%xzy+xzy)%xzy;
}
return ret;
}
四.无向图矩阵树定理
一些定义:
度数矩阵 (D):
邻接矩阵 (A):
基尔霍夫((kirchhoff))矩阵 (K): (K=D-A)
余子式:一个矩阵 (C) 的余子式 (M[i,j]) 表示 (C) 去掉第 (i) 行与第 (j) 列后得到的矩阵的行列式
定理内容:
无向图的生成树数量,等于基尔霍夫矩阵任意余子式 (M[i,i]) (!!!注意是 ("i,i"))的行列式
如果图不连通,则其任意余子式 (M[i,i]) 的行列式均为0
代码:
(模板题:(bzoj4031) ([HEOI2015]) 小 (Z) 的房间)
#include<cstdio>
#include<iostream>
#include<algorithm>
#define xzy 1000000000
using namespace std;
const int N = 85;
typedef int Mat[N][N];
typedef long long ll;
int Gauss(Mat A,int n){
int ret=1;
for(int j=1;j<=n;j++){
for(int i=j+1;i<=n;i++)
while(A[i][j]){
int t=A[j][j]/A[i][j];
for(int k=j;k<=n;k++){
A[j][k]=(A[j][k]-(ll)A[i][k]*t%xzy+xzy)%xzy;
swap(A[i][k],A[j][k]);
}
ret*=-1;
}
ret=((ll)ret*A[j][j]%xzy+xzy)%xzy;
}
return ret;
}
Mat a;
char ch[10][10];
int dir[4][2]={-1,0,1,0,0,-1,0,1};
int tot,id[10][10];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%s",ch[i]+1);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(ch[i][j]=='.') id[i][j]=++tot;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(ch[i][j]=='*') continue;
for(int k=0;k<4;k++)
if(id[i+dir[k][0]][j+dir[k][1]]){
a[id[i][j]][id[i][j]]++;
a[id[i][j]][id[i+dir[k][0]][j+dir[k][1]]]=-1;
}
}
printf("%d
",Gauss(a,tot-1));
return 0;
}
五.有向图矩阵树定理
一些定义:
入度矩阵 (D):
出度矩阵 (D):
邻接矩阵 (A):同上
内向生成树:生成树上的边为儿子指向父亲
外向生成树:生成树上的边为父亲指向儿子
扩展基尔霍夫矩阵(K): (K=D-A)
定理内容:
以 (root) 为根的生成树个数为 (K) 的余子式 (M[root,root]) 的行列式
其中:
若为内向生成树,则 (D) 为出度矩阵
若为外向生成树,则 (D) 为入度矩阵
代码:
(模板题:(bzoj5297) ([Cqoi2018]) 社交网络)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#define xzy 10007
using namespace std;
const int N = 255;
typedef long long ll;
typedef int Mat[N][N];
int Gauss(Mat A,int n){
int ret=1;
for(int j=1;j<=n;j++){
for(int i=j+1;i<=n;i++)
while(A[i][j]){
int t=A[j][j]/A[i][j];
for(int k=j;k<=n;k++){
A[j][k]=(A[j][k]-(ll)A[i][k]*t%xzy+xzy)%xzy;
swap(A[i][k],A[j][k]);
}
ret*=-1;
}
ret=((ll)ret*A[j][j]%xzy+xzy)%xzy;
}
return ret;
}
Mat a;
int main()
{
int n,m,x,y;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
scanf("%d%d",&x,&y);//y->x
x--; y--;
a[x][x]++; a[y][x]--;
}
printf("%d
",Gauss(a,n-1));
return 0;
}