图论x线性代数 学习笔记
最近几天讲图论,不得不猛搞,于是用了一两天时间:高斯消元 -> 行列式 -> Matrix-Tree定理 -> LGV引理
怕忘,写篇笔记。
高斯消元
一个用来解多元方程组的消元法。
就是以最常见的消元思路,从第一元到最后一元一个一个将除了本行系数以外的所有系数消为零,可以想象,如果我们将方程的系数用矩阵来表示,可能会长这样:
因为我们知道:
-
两方程交换,解不变
-
给一个方程的所有系数乘上
,解不变 -
将两个方程所有系数对应相加,解不变
每次消元,我们找到当前未知数所对应的列中最大的系数所在的行(也就是那个方程)交换到本行,再利用这个系数和上述第二条性质,把该未知数的其他系数消为
而此时原矩阵经过我们的操作一定会变成下三角矩阵,形如:
#include<bits/stdc++.h>
#define MAXN 102
using namespace std;
using db=double;
const db eps=1e-10;
int n;
db a[MAXN][MAXN];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n+1;j++)
cin>>a[i][j];
for(int i=1;i<=n;i++)
{
int max=i;
for(int j=i+1;j<=n;j++)
if(fabs(a[j][i])>fabs(a[max][i]))max=j;
for(int j=1;j<=n+1;j++)
swap(a[i][j],a[max][j]);
if(fabs(a[i][i])<eps){puts("No Solution");return 0;}
for(int j=1;j<=n;j++)
{
if(j==i)continue;
db tp=a[j][i]/a[i][i];
for(int k=i+1;k<=n+1;k++)
a[j][k]-=a[i][k]*tp;
}
}
for(int i=1;i<=n;i++)
printf("%.2lf\n",a[i][n+1]/a[i][i]);
return 0;
}
那么有了这个,我们能做什么呢?
行列式求值
行列式有一个很好的性质:
- 上三角/下三角矩阵的行列式等于对角线上值的乘积
而对于一个矩阵,
-
将矩阵的两行进行交换,其行列式的值会乘以
-
将矩阵的一行乘以一个系数加给另一行,行列式的值不变
然后我们再一看高斯消元,这不刚好嘛!
于是我们可以在 而不是根据定义的
#include<bits/stdc++.h>
#define MAXN 602
using namespace std;
using ll=long long;
int n,mod;
struct Matrix
{
ll a[MAXN][MAXN];
inline ll*operator[](const int&x){return a[x];}
inline ll det()
{
ll res=1,f=1;
for(int i=1;i<=n;i++)
{
int max=i;
for(int j=i+1;j<=n;j++)
if(a[j][i]>a[max][i])max=j;
if(i!=max)swap(a[i],a[max]),f=-f;
if(!a[i][i])return 0;
for(int j=i+1;j<=n;j++)
{
if(a[j][i]>a[i][i])swap(a[i],a[j]),f=-f;
while(a[j][i])
{
ll l=a[i][i]/a[j][i];
for(int k=i;k<=n;k++)
a[i][k]=(a[i][k]-l*a[j][k]%mod+mod)%mod;
swap(a[i],a[j]),f=-f;
}
}
(res*=a[i][i])%mod;
}
return ((res%mod)*f+mod)%mod;
}
}m;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>mod;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>m[i][j];
printf("%lld\n",m.det());
return 0;
}
这些就是前置知识,接下来是图论内容。
Matrix-Tree 定理
这个定理既然叫 Matrix-Tree 自然是有原因的,它告诉了我们如何求一个图的生成树个数。
对于一张无向图,定义它的度数矩阵为
然后可以由这两个矩阵相减得到新矩阵
那么这个无向图的生成树个数就是将
那有向图呢?
定义入度矩阵为
同理相减可得
那这个有向图的外向生成树的个数是
那带权呢?
那么行列式的值就等于
#include<bits/stdc++.h>
#define MAXN 302
using namespace std;
using ll=long long;
const int mod=1e9+7;
int n,m,t;
struct Matrix
{
ll a[MAXN][MAXN];
ll*operator[](int x){return a[x];}
inline Matrix operator-(Matrix b)const
{
Matrix res;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
res[i][j]=a[i][j]-b[i][j];
return res;
}
inline ll det()
{
ll res=1;int f=1;
for(int i=2;i<=n;i++)
{
int max=i;
for(int j=i+1;j<=n;j++)
if(a[j][i]>a[max][i])max=j;
if(i!=max)swap(a[i],a[max]),f=-f;
if(!a[i][i])return 0;
for(int j=i+1;j<=n;j++)
{
if(a[j][i]>a[i][i])swap(a[j],a[i]),f=-f;
while(a[j][i])
{
ll l=a[i][i]/a[j][i];
for(int k=i;k<=n;k++)
a[i][k]=(a[i][k]-l*a[j][k]%mod+mod)%mod;
swap(a[i],a[j]),f=-f;
}
}
(res*=a[i][i])%=mod;
}
return (res*f+mod)%mod;
}
}K;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>m>>t;
for(int i=1,u,v,w;i<=m;i++)
{
cin>>u>>v>>w;
if(t==0)
{
K[u][v]=(K[u][v]-w%mod+mod)%mod;
K[v][u]=(K[v][u]-w%mod+mod)%mod;
(K[u][u]+=w%mod)%=mod;
(K[v][v]+=w%mod)%=mod;
}
else
{
K[u][v]=(K[u][v]-w%mod+mod)%mod;
(K[v][v]+=w%mod)%=mod;
}
}
// for(int i=1;i<=n;i++)
// {
// for(int j=1;j<=n;j++)
// printf("%10lld ",K[i][j]);
// puts("");
// }
printf("%lld\n",K.det());
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App