矩阵树定理(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种潜在的天赋,但有 一些天赋必须是要有 ...
随机推荐
- iOS程序启动原理---iOS-Apple苹果官方文档翻译
本系列所有开发文档翻译链接地址:iOS7开发-Apple苹果iPhone开发Xcode官方文档翻译PDF下载地址 //转载请注明出处--本文永久链接:http://www.cnblogs.com/Ch ...
- js设置html区域隐藏和显示
if(message != "指派") { document.getElementById("appoint").style.display="non ...
- bzoj 2741 可持久化trie
首先我们设si为前i个数的xor和,那么对于询问区间[i,j]的xor和,就相当于si-1^sj,那么对于这道题的询问我们可以处理处si,然后对于询问[l,r],可以表示为在区间[l-1,r]里找两个 ...
- JS设计模式——3.封装与信息隐藏
封装.信息隐藏与接口的关系 信息隐藏是目的,封装是手段. 接口提供了一份记载着可供公共访问的方法的契约.它定义了两个对象间可以具有的关系.只要接口不变,这个关系的双方都是可以替换的. 一个理想的软件系 ...
- DataFrame衍生新特征操作
1.DataFrame中某一列的值衍生为新的特征 #将LBL1特征的值衍生为one-hot形式的新特征 piao=df_train_log.LBL1.value_counts().index #先构造 ...
- 【Eclipse】Elipse自定义library库并导入项目
1.定义像JRE System Library之类的库 (1)点击UserLibrary (2)如果没有就点击new新建一个user library,否则进行4 (3)向user library添加 ...
- PyQt实现测试工具
测试工具: 1. 基本界面实现: # coding:utf-8 import sys import os import os.path import re import time from PyQt4 ...
- [ python ] 正则表达式及re模块
正则表达式 正则表达式描述: 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符.及这些特定字符的组合,组成一个‘规则字符串’,这个‘规则字符串’用来 表达对字符串的一种过滤 ...
- java基础7 封装
面向对象的三大特征: 1.封装 (将一类属性封装起来,并提供set()和get()方法给其他对象设置和获取值.或者是将一个运算方法封装起来,其他对象需要此种做运算时,给此对象调用) 2.继承 ...
- Mysql查询语句的运行流程
我们先看一下MYsql的基本架构示意图: 大体来说,MySQL 可以分为 Server 层和存储引擎层两部分. Server 层包括连接器.查询缓存.分析器.优化器.执行器等,涵盖 MySQL 的大多 ...