专题做完了还是要说两句留下什么东西的。

矩阵树定理通俗点讲就是:

建立矩阵A[i][j]=-edge(i,j),(i!=j)。即矩阵这一项的系数是两点间直接相连的边数。

而A[i][i]=deg(i)。即对角线上都是这个点的度数。

得到这个矩阵后,随便删掉一行一列后进行高斯消元得到上三角矩阵,对角线上值的积就是生成树的个数。(就是行列式)

顺便提一下行列式的性质:

交换两行/列,行列式的值变为相反数。

一行的每一项减去另一行的若干倍,行列式不变。

一行的每一项都乘一个常数,行列式也乘这个常数。

到这里就够做题了。

T1:小Z的房间:

Descpiption:

你突然有了一个大房子,房子里面有一些房间。事实上,你的房子可以看做是一个包含n*m个格子的格状矩形,每个格子是一个房间或者是一个柱子。在一开始的时候,相邻的格子之间都有墙隔着。(n,m<=10)

你想要打通一些相邻房间的墙,使得所有房间能够互相到达。在此过程中,你不能把房子给打穿,或者打通柱子(以及柱子旁边的墙)。同时,你不希望在房子中有小偷的时候会很难抓,所以你希望任意两个房间之间都只有一条通路。现在,你希望统计一共有多少种可行的方案。Mod 10^9

板子。

 #include<cstdio>
#include<algorithm>
#define mod 1000000000
int ord[][],n,m,tim,A[][];char s[][];
void link(int a,int b){A[a][a]++;A[b][b]++;A[a][b]--;A[b][a]--;}
int Gauss(int ans=){
for(int i=;i<=tim;++i)for(int j=i+;j<=tim;++j)while(A[j][i]){
int d=A[i][i]/A[j][i];for(int k=i;k<=tim;++k)A[i][k]=(A[i][k]-1ll*d*A[j][k]%mod+mod)%mod;
std::swap(A[i],A[j]);ans*=-;
}for(int i=;i<=tim;++i)ans=1ll*ans*A[i][i]%mod;return (ans+mod)%mod;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;++i)scanf("%s",s[i]+);
for(int i=;i<=n;++i)for(int j=;j<=m;++j)if(s[i][j]=='.')ord[i][j]=++tim;
for(int i=;i<=n;++i)for(int j=;j<=m;++j)if(s[i][j]=='.'){
if(s[i-][j]=='.')link(ord[i-][j],ord[i][j]);
if(s[i][j-]=='.')link(ord[i][j-],ord[i][j]);
}
tim--;printf("%d\n",Gauss());
}

T2:重建:

Description:

T 国有n(n<=50)个城市,用若干双向道路连接。一对城市之间至多存在一条道路。
在一次洪水之后,一些道路受损无法通行。虽然已经有人开始调查道路的损毁情况,但直到现在几乎没有消息传回。
幸运的是,此前 T 国政府调查过每条道路的强度,现在他们希望只利用这些信息估计灾情。
具体地,给定每条道路在洪水后仍能通行的概率,请计算仍能通行的道路恰有N-1条,且能联通所有城市的概率。

spj:相对误差<1e-4

变元的了。

就是边带权,要求出所有生成树边权积的和。

那么统计度数和边权的时候都不再++,--,按照边权来就可以了。

但是这道题求的没有这么简单。

求的是恰好形成一棵树,不能有多边。即求$\sum\limits_{tree} \prod\limits_{i \in tree}w_i \prod\limits_{i \notin tree}(1-w_i)$

不在树里的不好处理,所以化一下得到$\sum\limits_{tree} \prod\limits_{i \in tree}\frac{w_i}{1-w_i} \prod\limits_i(1-w_i)$

然后就得到了新的边权。

要注意设个eps,当$1-w_i$很小时除法容易锅,如果它小于eps就把它强制置为eps。

 #include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
long double A[][];int n;
long double Gauss(){long double ans=;
for(int i=;i<n;++i){
long double mx=;int pt;
for(int j=i;j<n;++j)if(fabs(A[j][i])>mx)pt=j,mx=fabs(A[j][i]);
if(pt!=i)swap(A[pt],A[i]);
for(int j=i+;j<n;++j){
long double rate=A[j][i]/A[i][i];
for(int k=i;k<=n;++k)A[j][k]-=rate*A[i][k];
}
}
for(int i=;i<n;++i)ans*=A[i][i];return ans;
}
int main(){
scanf("%d",&n);long double pans=;
for(int i=;i<=n;++i)for(int j=;j<=n;++j)scanf("%Lf",&A[i][j]);
for(int i=;i<=n;++i)for(int j=i+;j<=n;++j)pans*=.0L-A[i][j]<1e-?1e-:.0L-A[i][j];
for(int i=;i<=n;++i)for(int j=;j<=n;++j)A[i][j]/=.0L-A[i][j]<1e-?1e-:.0L-A[i][j];
for(int i=;i<=n;++i)for(int j=;j<=n;++j)if(i!=j)A[i][i]+=A[i][j];
for(int i=;i<=n;++i)for(int j=;j<=n;++j)if(i!=j)A[i][j]=-A[i][j];
printf("%.10Lf\n",Gauss()*pans);
}

T3:2467生成树:

Description:

有一种图形叫做五角形圈。一个五角形圈的中心有1个由n个顶点和n条边组成的圈。在中心的这个n(n<=100)边圈的每一条边同时也是某一个五角形的一条边,一共有n个不同的五角形。这些五角形只在五角形圈的中心的圈上有公共的顶点。如图0所示是一个4-五角形圈。 现在给定一个n五角形圈,你的任务就是求出n五角形圈的不同生成树的数目。还记得什么是图的生成树吗?一个图的生成树是保留原图的所有顶点以及顶点的数目减去一这么多条边,从而生成的一棵树。 注意:在给定的n五角形圈中所有顶点均视为不同的顶点。mod2007

板子。注意判断n=2

 #include<cstdio>
#include<algorithm>
#define mod 2007
int A[][],n;
int Gauss(int ans=){n--;
for(int i=;i<=n;++i)for(int j=i+;j<=n;++j)while(A[j][i]){
int d=A[i][i]/A[j][i];for(int k=i;k<=n;++k)A[i][k]=(A[i][k]+mod-A[j][k]*d%mod)%mod;
std::swap(A[i],A[j]);ans*=-;
}for(int i=;i<=n;++i)ans=ans*A[i][i]%mod;return (ans+mod)%mod;
}
int main(){
int t;scanf("%d",&t);
while(t--){
scanf("%d",&n);n<<=;
for(int i=;i<n;++i)for(int j=;j<n;++j)A[i][j]=;
for(int i=;i<n;++i)A[i][i]=i%==?:;
for(int i=;i<n;++i)A[i][i+]--,A[i+][i]--;
A[][n-]--,A[n-][]--;
for(int i=;i<n;i+=)A[i][i+]--,A[i+][i]--;
printf("%d\n",Gauss());
}
}

T4:黑暗前的幻想乡

Description:

四年一度的幻想乡大选开始了,最近幻想乡最大的问题是很多来历不明的妖怪涌入了幻想乡,扰乱了幻想乡昔日的秩序。但是幻想乡的建制派妖怪(人类)博丽灵梦和八云紫等人整日高谈所有妖怪平等,幻想乡多元化等等,对于幻想乡目前面临的种种大问题却给不出合理的解决方案。

风见幽香是幻想乡里少有的意识到了问题严重性的大妖怪。她这次勇敢地站了出来参加幻想乡大选,提出包括在幻想乡边境建墙(并让人类出钱),大力开展基础设施建设挽回失业率等一系列方案,成为了大选年出人意料的黑马并顺利地当上了幻想乡的大统领。

幽香上台以后,第一项措施就是要修建幻想乡的公路。幻想乡一共有n(n<=17)个城市,之前原来没有任何路。幽香向选民承诺要减税,所以她打算只修n-1条公路将这些城市连接起来。但是幻想乡有正n-1个建筑公司,每个建筑公司都想在修路地过程中获得一些好处。虽然这些建筑公司在选举前没有给幽香钱,幽香还是打算和他们搞好关系,因为她还指望他们帮她建墙。所以她打算让每个建筑公司都负责一条路来修。

每个建筑公司都告诉了幽香自己有能力负责修建的路是哪些城市之间的。所以幽香打算n-1条能够连接幻想乡所有城市的边,然后每条边都交给一个能够负责该边的建筑公司修建,并且每个建筑公司都恰好修建一条边。

幽香现在想要知道一共有多少种可能的方案呢?两个方案不同当且仅当它们要么修的边的集合不同,要么边的分配方式不同。mod1e9+7

数据范围很小,考虑枚举子集进行容斥。

奇加偶减,然后就是板子了。

 #include<cstdio>
#include<algorithm>
#define mod 1000000007
int n,A[][],c[][][],ans;
int Gauss(){int ans=;
for(int i=;i<n;++i)for(int j=i+;j<n;++j)while(A[j][i]){
int d=A[i][i]/A[j][i];for(int k=i;k<n;++k)A[i][k]=(A[i][k]-1ll*A[j][k]*d%mod+mod)%mod;
std::swap(A[i],A[j]);ans*=-;
}for(int i=;i<n;++i)ans=1ll*ans*A[i][i]%mod;return ans;
}
int main(){
scanf("%d",&n);
for(int i=;i<n;++i){
int k,x,y;scanf("%d",&k);
while(k--)scanf("%d%d",&x,&y),c[i][x][x]++,c[i][y][y]++,c[i][x][y]--,c[i][y][x]--;
}
for(int st=;st<<<n-;++st){
for(int i=;i<n;++i)for(int j=;j<n;++j)A[i][j]=;
for(int l=;l<n;++l)if(st&<<l-)
for(int i=;i<n;++i)for(int j=;j<n;++j)A[i][j]+=c[l][i][j];
int pt=;for(int i=st;i;i^=i&-i)pt*=-;if(n&^)pt*=-;//printf("%d %d\n",st,pt);
ans=(0ll+ans+mod+pt*Gauss())%mod;//printf("%d\n",ans);
}printf("%d\n",ans);
}

T5:最小生成树计数

Description:

原题来自:JSOI 2008

现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树。mod31011(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。对于全部数据,n<=100,m<=1000。

数据保证不会出现自回边和重边。

注意:具有相同权值的边不会超过10条。

最后那个注意是真的要注意。。。

先来两发结论:

1。在不同的最小生成树中,每种权值的边用的数量是一定的。

2。在不同的最小生成树中,每种权值的边都加入完后,图的联通性是一定的。

(即如,你用并查集维护的话,如果每次合并都把小编号的当成根,那么得到并查集都完全一样)

仔细想一想,其实都不难证。

然后你只要状压每种边权的10条边用了哪些就好了。

也可以用matrix_tree做。但是我打的搜索。

 #include<cstdio>
#include<algorithm>
#include<unordered_map>
#include<vector>
using namespace std;
unordered_map<int,int>M;
struct edge{
int a,b,v;
friend bool operator<(edge A,edge B){
return A.v<B.v;
}
}E[];
vector<edge>v[];
int n,m,f[],cnt,uc[],p[][],ans=;
int find(int k){return f[k]==k?k:f[k]=find(f[k]);}
void merge(int a,int b){if(a<b)f[b]=a;else f[a]=b;}
int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;++i)f[i]=i;
for(int i=;i<=m;++i)scanf("%d%d%d",&E[i].a,&E[i].b,&E[i].v);
sort(E+,E++m);
for(int i=;i<=m;++i)if(M[E[i].v]!=cnt||cnt==)M[E[i].v]=++cnt;
for(int i=;i<=m;++i)E[i].v=M[E[i].v];
for(int i=;i<=m;++i)v[E[i].v].push_back(E[i]);
for(int i=;i<=cnt;++i){
for(int j=;j<v[i].size();++j)if(find(v[i][j].a)!=find(v[i][j].b))
merge(f[v[i][j].a],f[v[i][j].b]),uc[i]++;
for(int j=;j<=n;++j)p[i][j]=find(j);
}
for(int i=;i<=n;++i)if(find(i)!=){puts("");return ;}
for(int i=;i<=n;++i)p[][i]=i;
for(int i=;i<=cnt;++i){
int pl=;//printf("%d %d\n",i,pl);
for(int j=;j<<<v[i].size();++j){
for(int l=;l<=n;++l)f[l]=p[i-][l];
for(int l=;l<v[i].size();++l)if(j&<<l)
if(find(v[i][l].a)==find(v[i][l].b))goto B;
else merge(f[v[i][l].a],f[v[i][l].b]);
for(int l=;l<=n;++l)if(find(l)!=p[i][l])goto B;
pl++;B:;
}
ans=ans*pl%;//printf("%d %d\n",i,pl);
}printf("%d\n",ans);
}

T6:轮状病毒

Description:

轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的。一个N轮状基由圆环上N个不同的基原子 和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道。如下图所示

N轮状病毒的产生规律是在一个N轮状基中删去若干条边,使得各原子之间有唯一的信息通道,例如共有16个不 同的3轮状病毒,如下图所示

现给定n(N<=100),编程计算有多少个不同的n轮状病毒

感觉少了点什么。

对,你没看错,没有模数。需要高精,__int128卡不过的。

那么直接跑Gauss得T飞吧。

所以正确的姿势是,小点matrix_tree打表找规律。大点dp写高精。

给出dp式子$dp[i]=dp[i-1]\times 3 - dp[i-2] +2$

然后就打个高精就行。

 #include<cstdio>
int n;
struct bigint{
#define mod 100000000
int a[];
friend void operator+=(bigint &a,bigint b){
for(int i=;~i;--i)a.a[i]+=b.a[i];
for(int i=;i<=;++i)if(a.a[i]>=mod)a.a[i]-=mod,a.a[i+]++;
}
friend void operator-=(bigint &a,bigint b){
for(int i=;~i;--i)a.a[i]-=b.a[i];
for(int i=;i<=;++i)if(a.a[i]<)a.a[i]+=mod,a.a[i+]--;
}
void print(int i=){
for(;~i;--i)if(a[i]){printf("%d",a[i]);break;}
for(--i;~i;--i)printf("%08d",a[i]);puts("");
}
}ldp,nw,nxt;
int main(){
nw.a[]=;int n;scanf("%d",&n);n--;
while(n--){
nxt=nw;nxt+=nw;nxt+=nw;nxt-=ldp;nxt.a[]+=;
ldp=nw;nw=nxt;
}nw.print();
}

[专题总结]矩阵树定理Matrix_Tree及题目&题解的更多相关文章

  1. loj6271 「长乐集训 2017 Day10」生成树求和 加强版(矩阵树定理,循环卷积)

    loj6271 「长乐集训 2017 Day10」生成树求和 加强版(矩阵树定理,循环卷积) loj 题解时间 首先想到先分开三进制下每一位,然后每一位分别求结果为0,1,2的树的个数. 然后考虑矩阵 ...

  2. 【算法】Matrix - Tree 矩阵树定理 & 题目总结

    最近集中学习了一下矩阵树定理,自己其实还是没有太明白原理(证明)类的东西,但想在这里总结一下应用中的一些细节,矩阵树定理的一些引申等等. 首先,矩阵树定理用于求解一个图上的生成树个数.实现方式是:\( ...

  3. CF917D. Stranger Trees & TopCoder13369. TreeDistance(变元矩阵树定理+高斯消元)

    题目链接 CF917D:https://codeforces.com/problemset/problem/917/D TopCoder13369:https://community.topcoder ...

  4. 【LOJ#6072】苹果树(矩阵树定理,折半搜索,容斥)

    [LOJ#6072]苹果树(矩阵树定理,折半搜索,容斥) 题面 LOJ 题解 emmmm,这题似乎猫讲过一次... 显然先\(meet-in-the-middle\)搜索一下对于每个有用的苹果数量,满 ...

  5. 【bzoj4596】[Shoi2016]黑暗前的幻想乡 容斥原理+矩阵树定理

    题目描述 给出 $n$ 个点和 $n-1$ 种颜色,每种颜色有若干条边.求这张图多少棵每种颜色的边都出现过的生成树,答案对 $10^9+7$ 取模. 输入 第一行包含一个正整数 N(N<=17) ...

  6. CSU 1805 Three Capitals(矩阵树定理+Best定理)

    http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1805 题意: A和B之间有a条边,A和G之间有b条边,B和G之间有c条边.现在从A点出发走遍所 ...

  7. BZOJ 2467: [中山市选2010]生成树(矩阵树定理+取模高斯消元)

    http://www.lydsy.com/JudgeOnline/problem.php?id=2467 题意: 思路:要用矩阵树定理不难,但是这里的话需要取模,所以是需要计算逆元的,但是用辗转相减会 ...

  8. BZOJ 1002 轮状病毒 矩阵树定理

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1002 题目大意: 给定n(N<=100),编程计算有多少个不同的n轮状病毒 思路 ...

  9. 【bzoj5133】[CodePlus2017年12月]白金元首与独舞 并查集+矩阵树定理

    题目描述 给定一个 $n\times m$ 的方格图,每个格子有 ↑.↓.←.→,表示从该格子能够走到相邻的哪个格子.有一些格子是空着的,需要填上四者之一,需要满足:最终的方格图中,从任意一个位置出发 ...

随机推荐

  1. ShaderHelper2 组件升级,支持自动枚举参数!

    ShaderHelper2 组件新体验视频演示: https://www.bilibili.com/video/av69314195/ ShaderHelper2 组件我们已经介绍过两次了,不了解的伙 ...

  2. Scala 学习笔记之集合(5)

    import collection.mutable.Buffer object CollectionDemo6 { def main(args: Array[String]): Unit = { // ...

  3. 三个Eclipse下的Debug的使用场景(五)

    本文链接:https://blog.csdn.net/u011781521/article/details/55000066    http://blog.csdn.net/u010075335/ar ...

  4. Faker——生成测试数据的PHP类库

    工作上用的是TP框架,每次测试功能的时候都要手动添加测试数据,词穷起名总是起一些test1.test2这种low到爆炸的用户名,这让我很难受.稍微翻阅了一些资料,发现laravel有一个生成测试数据的 ...

  5. 小白学 Python(2):基础数据类型(上)

    人生苦短,我选Python 引言 前文传送门 小白学 Python(1):开篇 接触一门新的语言,肯定要先了解它的基础数据类型.啥?你问我为啥要先了解基础数据类型? 为了你的生命安全,还是乖乖听我 B ...

  6. Redis未授权访问写Webshell和公私钥认证获取root权限

    0x01 什么是Redis未授权访问漏洞 Redis 默认情况下,会绑定在 0.0.0.0:,如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源 ip 访问等,这样将会将 Redis 服 ...

  7. [51nod1670] 打怪兽

    lyk在玩一个叫做“打怪兽”的游戏.游戏的规则是这样的.lyk一开始会有一个初始的能量值.每次遇到一个怪兽,若lyk的能量值>=怪兽的能量值,那么怪兽将会被打败,lyk的能量值增加1,否则lyk ...

  8. 安装并使用SourceTree进行代码管理(Mac环境)

    应用场景 对于我们开发人员来说,熟练使用Git是最基本的技能之一.SourceTree又是一款比较好的Git UI工具,是 Windows 和Mac OS X 下免费的 Git 和 Hg 客户端,主要 ...

  9. Docker卷

    要解决的问题:在移除了现有容器或者添加了新容器时,之前容器的数据无法访问. 为避免上述问题,Docker提供了以下策略来持久化数据 tmpfs挂载 绑定挂载 卷 1.tmpfs挂载 2.绑定挂载 将D ...

  10. 9.Nginx常用模块

    1.nginx开启目录浏览 提供下载功能 默认情况下,网站返回index指定的主页,若该网站不存在主页,则将请求交给autoindex模块 如果开启autoindex模块,则提供一个下载的页面, 如果 ...