矩阵树定理(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种潜在的天赋,但有 一些天赋必须是要有 ...
随机推荐
- script标签中type为<script type="text/x-template">是个啥
写过一点前端的都会碰到需要使用JS字符串拼接HTML元素然后append到页面DOM树上的情况,一般的写法都是使用+号以字符串的形式拼接,如果是短点的还好,如果很长很长的话就会拼接到令人崩溃了. 比如 ...
- 笔记本自开wifi设置
笔记本自开wifi设置 是这样的有些笔记本他自身就可以放出热点供其他的小伙伴们连接,不用非得去下专门的工具有些笔记本的网卡是自带支持双收发的(这里注意我指的是有些笔记本不是全部) 命令我已经写出来了 ...
- 中高级JAVA面试知识点(个人整理)
JVM运行时数据区域 方法区: 用 于存储虚拟机加载的类信息,常量,静态变量,JIT编译后的代码,所有线程共享 堆:所有线程共享,用来存储实例对象. 虚拟机栈:线程私有,生命周期与线程相同,每个方法被 ...
- php pdo封装类
class MYPDO { protected static $_instance = null; protected $dbname = ''; protected $dsn; protected ...
- python基础(8)--迭代器、生成器、装饰器
1.迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一大优 ...
- Codeigniter处理用户登录验证后URL跳转
涉及到My_Controller.php以及登录验证模块User.php,代码如下: My_Controller.php class MY_Controller extends CI_Controll ...
- 前端JS框架系列之requireJS基础学习
1 背景 伴随着项目功能的不断扩充,客户体验的不断完善,实现交互逻辑的JS代码变得越来越多.起初,为了管理JS代码,我们把JS从页面中解放出来独立成文件,接着又把相似的交互代码提取到公共的JS页面中. ...
- lr如何屏蔽全局变量的影响
首先要熟悉C语言的全局变量和局部变量的含义: C语言中的变量详解 先说说变量的作用域,比如,在函数中,形参变量只是在被调用期间才分配内存单元,调用结束立即释放.这就说明形参变量只有在函授内才是有效的, ...
- JavaScript 实现数组去重
JavaScript 实现数组去重 演示Demo 数组去重 // 方法一 function unique1(a) { var res = []; for (var i = 0, len = a.len ...
- github 笔记(一)
笔记预留 0. echo "# Try" >> README.md git init git add README.md git commit -m "fir ...