矩阵树定理(Matrix Tree)学习笔记
如果不谈证明,稍微有点线代基础的人都可以在两分钟内学完所有相关内容。。
行列式随便找本线代书看一下基本性质就好了。
学习资源:
https://www.cnblogs.com/candy99/p/6420935.html
http://blog.csdn.net/Marco_L_T/article/details/72888138
首先是行列式对几个性质(基本上都是用数学归纳法证):
1.交换两行(列),行列式取相反数
2.由1.得若存在两行(列)完全相同则行列式为0
3.上(下)三角行列式即主对角线值之积
只有这三条用得上。
然后就可以直接上Matrix Tree定理了:一个无向图的邻接矩阵减去度数矩阵得到的矩阵的任意n-1阶子矩阵的行列式的绝对值等于其有标号生成树的数目。
其中邻接矩阵-度数矩阵即为基尔霍夫矩阵(又称拉普拉斯算子)。
加强版:有向图的树形图(从根可以走到任意点)个数,将上面的“度数矩阵”改为“入度矩阵即可”(见第二份链接)
若求以x为根的外向树数量,则求删去第x行与第x列的n-1阶子矩阵的行列式即可。
关于行列式的算法,按定义朴素跑复杂度是阶乘级别的,利用上面的性质,初等行变换使之成为上三角矩阵即可。(实际上就是高斯消元)。注意高消中基准元要选绝对值最大的,以及注意判0退出。
下面是几道裸题:
SPOJ Highways 裸题
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
using namespace std; const int N=;
const double eps=1e-; int T,n,m,u,v;
double a[N][N]; void Gauss(){
n--;
rep(i,,n){
int r=i;
rep(j,i+,n) if (fabs(a[j][i])>fabs(a[r][i])) r=j;
if (fabs(a[r][i]<eps)) { puts(""); return; }
if (r!=i) rep(k,,n) swap(a[r][k],a[i][k]);
rep(j,i+,n){
double t=a[j][i]/a[i][i];
rep(k,i,n) a[j][k]-=t*a[i][k];
}
}
double ans=;
rep(i,,n) ans*=a[i][i];
printf("%.0f\n",abs(ans));
} int main(){
for (scanf("%d",&T); T--; ){
scanf("%d%d",&n,&m);
memset(a,,sizeof(a));
rep(i,,m) scanf("%d%d",&u,&v),a[u][u]++,a[v][v]++,a[u][v]--,a[v][u]--;
Gauss();
}
return ;
}
BZOJ4766:
先手工构造出矩阵然后观察规律求出公式。
https://blog.sengxian.com/solutions/bzoj-4766
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll; ll n,m,P;
ll mod(ll x){ return (x<P) ? x : x-P; } ll mul(ll a,ll b){
ll res=;
for (; b; b>>=,a=mod(a+a))
if (b & ) res=mod(res+a);
return res;
} ll pow(ll a,ll b){
ll res=;
for (; b; b>>=,a=mul(a,a))
if (b & ) res=mul(res,a);
return res;
} int main(){
scanf("%lld%lld%lld",&n,&m,&P);
printf("%lld\n",mul(pow(n,m-),pow(m,n-)));
return ;
}
BZOJ4031 裸题
这里又个trick,高斯消元的时候因为模数是个合数不好求逆元,所以用辗转相除的方法做就好了。
就是不停对两行相互进行初等行变换直到其中一行第一个数变为0,这样复杂度是log的,并且保证膜意义下不会出错。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
typedef long long ll;
using namespace std; const int N=,md=;
int n,m,a[N][N],id[N][N],tot;
char s[N][N]; void Gauss(int n){
int s=;
rep(i,,n){
int r=i;
rep(j,i+,n) if (a[j][i]>a[r][i]) r=j;
if (!a[r][i]) { puts(""); return; }
if (i!=r){
s^=;
rep(k,i,n) swap(a[i][k],a[r][k]);
}
rep(j,i+,n){
while (a[j][i]){
ll t=a[j][i]/a[i][i];
rep(k,i,n) a[j][k]=(a[j][k]-t*a[i][k]%md+md)%md;
if (!a[j][i]) break;
s^=;
rep(k,i,n) swap(a[i][k],a[j][k]);
}
}
}
ll ans=;
rep(i,,n) ans=ans*a[i][i]%md;
if (s) ans=(md-ans)%md;
printf("%lld\n",ans);
} void work(){
rep(i,,m) rep(j,,n) if (s[i][j]=='.') id[i][j]=++tot;
rep(i,,m) rep(j,,n) if (id[i][j]){
int u=id[i][j],v;
if (i!= && s[i-][j]=='.')
v=id[i-][j],a[u][u]++,a[v][v]++,a[u][v]--,a[v][u]--;
if (j!= && s[i][j-]=='.')
v=id[i][j-],a[u][u]++,a[v][v]++,a[u][v]--,a[v][u]--;
}
rep(i,,m*n) rep(j,,m*n) a[i][j]=(a[i][j]+md)%md;
} int main(){
freopen("bzoj4031.in","r",stdin);
freopen("bzoj4031.out","w",stdout);
scanf("%d%d",&m,&n);
rep(i,,m) scanf("%s",s[i]+);
work(); Gauss(tot-);
return ;
}
矩阵树定理(Matrix Tree)学习笔记的更多相关文章
- 【Learning】矩阵树定理 Matrix-Tree
矩阵树定理 Matrix Tree 矩阵树定理主要用于图的生成树计数. 看到给出图求生成树的这类问题就大概要往这方面想了. 算法会根据图构造出一个特殊的基尔霍夫矩阵\(A\),接着根据矩阵树定理, ...
- @总结 - 7@ 生成树计数 —— matrix - tree 定理(矩阵树定理)与 prüfer 序列
目录 @0 - 参考资料@ @0.5 - 你所需要了解的线性代数知识@ @1 - 矩阵树定理主体@ @证明 part - 1@ @证明 part - 2@ @证明 part - 3@ @证明 part ...
- 【算法】Matrix - Tree 矩阵树定理 & 题目总结
最近集中学习了一下矩阵树定理,自己其实还是没有太明白原理(证明)类的东西,但想在这里总结一下应用中的一些细节,矩阵树定理的一些引申等等. 首先,矩阵树定理用于求解一个图上的生成树个数.实现方式是:\( ...
- 矩阵树定理&BEST定理学习笔记
终于学到这个了,本来准备省选前学来着的? 前置知识:矩阵行列式 矩阵树定理 矩阵树定理说的大概就是这样一件事:对于一张无向图 \(G\),我们记 \(D\) 为其度数矩阵,满足 \(D_{i,i}=\ ...
- Note -「矩阵树定理」学习笔记
大概--会很简洁吧 qwq. 矩阵树定理 对于无自环无向图 \(G=(V,E)\),令其度数矩阵 \(D\),邻接矩阵 \(A\),令该图的 \(\text{Kirchhoff}\) 矩阵 \ ...
- 珂朵莉树(Chtholly Tree)学习笔记
珂朵莉树(Chtholly Tree)学习笔记 珂朵莉树原理 其原理在于运用一颗树(set,treap,splay......)其中要求所有元素有序,并且支持基本的操作(删除,添加,查找......) ...
- 2018.09.16 spoj104Highways (矩阵树定理)
传送门 第一次写矩阵树定理. 就是度数矩阵减去邻接矩阵之后得到的基尔霍夫矩阵的余子式的行列式值. 这个可以用高斯消元O(n3)" role="presentation" ...
- luoguP3317 [SDOI2014]重建 变元矩阵树定理 + 概率
首先,我们需要求的是 $$\sum\limits_{Tree} \prod\limits_{E \in Tree} E(u, v) \prod\limits_{E \notin Tree} (1 - ...
- 【BZOJ4894】天赋(矩阵树定理)
[BZOJ4894]天赋(矩阵树定理) 题面 BZOJ Description 小明有许多潜在的天赋,他希望学习这些天赋来变得更强.正如许多游戏中一样,小明也有n种潜在的天赋,但有 一些天赋必须是要有 ...
随机推荐
- 【BZOJ】3302: [Shoi2005]树的双中心 && 2103: Fire 消防站 && 2447: 消防站
[题意]给定带点权树,要求选择两个点x,y,满足所有点到这两个点中较近者的距离*点权的和最小.n<=50000,h<=100. [算法]树的重心 [题解]代码参考自:cgh_Andy 观察 ...
- js写弹窗
1.先来看弹窗的模样 点击“弹出窗口”后会弹出下面窗口 2.下面是实现弹出窗口的代码,其中引入的jquery一般自己有,没有的话可以从网上下载.tanchuang.js和tanchuang.css写在 ...
- Android SDK的安装与环境变量的配置
配置Andriod环境变量前提是要先安装好JAVA环境 1.下载Android SDK,点击安装,放在任意不含空格.特殊符号和中文的路径即可. 2.默认路径安装后,安装完成,开始配置环境变量. 3.打 ...
- Python中单引号,双引号,三引号
1.单引号与双引号的区别 s1=‘let‘s go’(明显我们是想用单引号表示let’s go这个字符串的,但是python只知道用‘’来表示字符串,所以python就把字符串中的‘字符当成单引号处理 ...
- Linux下libevent安装与示例
http://www.cnblogs.com/kunhu/p/3632225.html
- Django 自定义分页类
分页类代码: class Page(object): ''' 自定义分页类 可以实现Django ORM数据的的分页展示 输出HTML代码: 使用说明: from utils import mypag ...
- rabbitmq集群搭建方法简介(测试机linux centos)【转】
本文将介绍四台机器搭建rabbitmq集群: rabbitmq IP和主机名(每台机器已安装RabbitMQ 3.5.6, Erlang 18.1) 192.168.87.73 localhost73 ...
- java程序out of memory【转】
相信大家都有感触,线上服务内存OOM的问题,是最难定位的问题,不过归根结底,最常见的原因: 本身资源不够 申请的太多 资源耗尽 58到家架构部,运维部,58速运技术部联合进行了一次线上服务内存OOM问 ...
- 64.Minimum Path Sum---dp
题目链接:https://leetcode.com/problems/minimum-path-sum/description/ 题目大意:从左上到右下的路径中,找出路径和最小的路径(与62,63题相 ...
- myeclipse/eclipse安装反编译插件jadclipse
jad是一个使用比较广泛的Java反编译软件,jadClipse是jad在eclipse下的插件,下面像大家介绍下如何将jadclipse加入到myeclipse/eclipse中. 文件下载 (1) ...