传送门

以前用dfsdfsdfs做的,用基尔霍夫矩阵真的玄啊

首先这道题有这么几个定理:(来自Z-Y-Y-S的博客)
定理一:如果 A,BA, BA,B 同为 GGG 的最小生成树,且 AAA 的边权从小到大为 w(a1),w(a2),w(a3),⋯w(an)w(a_1), w(a_2), w(a_3), \cdots w(a_n)w(a1​),w(a2​),w(a3​),⋯w(an​),BBB 的边权从小到大为 w(b1),w(b2),w(b3),⋯w(bn)w(b_1), w(b_2), w(b_3), \cdots w(b_n)w(b1​),w(b2​),w(b3​),⋯w(bn​),则有 w(ai)=w(bi)w(a_i) = w(b_i)w(ai​)=w(bi​)。
证明:设 A,BA, BA,B 第一个不同的边的下标为 iii,不妨设 w(ai)≤w(bi)w(a_i) \le w(b_i)w(ai​)≤w(bi​),如果不存在这样的 iii,无需证明。
情况一:aia_iai​ 在 BBB 中,为 bjb_jbj​。那么显然有 j>ij>ij>i(否则 iii 不是第一个不同的边),则有 w(ai)≤w(bi)≤w(bj)=w(ai)w(a_i)\le w(b_i) \le w(b_j) = w(a_i)w(ai​)≤w(bi​)≤w(bj​)=w(ai​),所以有 w(ai)=w(bi)=w(bj)w(a_i) = w(b_i) = w(b_j)w(ai​)=w(bi​)=w(bj​),所以可以调换 bi,bjb_i, b_jbi​,bj​ 的位置,BBB 的权值排列不会改变, AAA 与 BBB 这样前 iii 条边均为相等,可以递归下去证明。
情况二:aia_iai​ 不在 BBB 中。考虑将 aia_iai​ 加入 BBB,则形成了一个环,环中的权值 v≤w(ai)v\le w(a_i)v≤w(ai​)(否则 BBB 不是最小生成树),且一定有一条边 bjb_jbj​ 不在 BBB 中,此时仍有 j>ij>ij>i(否则 iii 不是第一个不同的边),所以有 w(ai)≤w(bi)≤w(bj)≤w(ai)w(a_i)\le w(b_i) \le w(b_j) \le w(a_i)w(ai​)≤w(bi​)≤w(bj​)≤w(ai​),所以仍有 w(ai)=w(bi)=w(bj)w(a_i) = w(b_i) = w(b_j)w(ai​)=w(bi​)=w(bj​),可以将 bjb_jbj​ 替换为 aia_iai​,BBB 的权值排列不会改变且仍为最小生成树,仍然调换 bi,bjb_i, b_jbi​,bj​ 的位置,BBB 的权值排列仍会改变,这样 AAA 与 BBB 前 iii 条边均为相等,可以递归下去证明。这样换边不会有问题,因为 Kruskal 算法中唯一的状态就是连通性,我们没有改变其连通性,所以是可以递归证明的。

定理二:如果 A,BA, BA,B 同为 GGG 的最小生成树,如果 A,BA, BA,B 都从零开始从小到大加边(AAA 加 AAA 的边,BBB 加 BBB 的边)的话,每种权值加完后图的联通性相同。
证明:归纳法证明,没有边时显然成立,假设对于权值小于 vvv 的成立。考虑权值为 vvv 的边,如果连通性不相同,必然存在 u,vu, vu,v 两点间连通性不同,假设 AAA 中 u,vu, vu,v 联通,根据 A,BA, BA,B 所有小于 vvv 的边连通性相同,所以必然存在一条 u→vu\rightarrow vu→v 权值为 vvv 的边,而根据 Kruskal 算法的执行过程, BBB 不可能不加这条边,所以两棵最小生成树 A,BA, BA,B 各自权值小于等于 vvv 的边仍然满足连通性相同。由归纳法可知定理二成立。

定理三:如果在最小生成树 AAA 中权值为 vvv 的边有 kkk 条,用任意 kkk 条权值为 vvv 的边替换 AAA 中的权为 vvv 的边且不产生环的方案都是一棵合法最小生成树。
证明:根据之前的定理,其余的边造成的连通性是定的,权值和也是定的,那么选 kkk 条不产生环一定能形成一棵树,而且权值与最小生成树的权值一样,故也是最小生成树。

有了这些定理,就可以基尔霍夫矩阵来算方案,每次乘起来,但算的时候要先“缩点”,其实就是排个序去重之类的,然后算完方案随便找一种连起来,但注意算方案的时候有可能不能构成生成树,还需要先把图再连一下使它能有生成树。

细节很多,写的时候一定要脑子清楚
代码如下:(改动比较多,有点丑)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 105
#define M 1005
#define LL long long
#define int LL
using namespace std;inline int rd(){int x=0,f=1;char c=' ';while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();return x*f;
}int n,m,a[N][N],fa[N],fa2[N],ans=1,c[N<<1],sum;
const int mod=31011;struct EDGE{int fr,to,w;bool operator <(const EDGE &x) const{return w<x.w;}
}edge[M],tmp[M];inline int Matrix_tree(int tot){for(int i=1;i<tot;i++)for(int j=1;j<tot;j++)a[i][j]=(a[i][j]+mod)%mod;int ans=1,f=1;for(int i=1;i<tot;i++){for(int j=i+1;j<tot;j++){if(!a[j][i]) continue;int A=a[i][i],B=a[j][i];while(B){int t=A/B;A%=B; swap(A,B);for(int k=i;k<tot;k++) a[i][k]=(a[i][k]-1LL*t*a[j][k]+mod)%mod;for(int k=i;k<tot;k++) swap(a[i][k],a[j][k]); f=-f;}}if(!a[i][i]) return 0;ans=1LL*ans*a[i][i]%mod;}if(f==-1) ans=mod-ans%mod;return (ans+mod)%mod;
}inline int find(int x){if(x==fa[x]) return x;return fa[x]=find(fa[x]);
}
inline int find2(int x){if(x==fa2[x]) return x;return fa2[x]=find2(fa2[x]);
}inline int solve(int l,int r){int cnt=0,num=0;for(int i=l;i<=r;i++){int x=find(edge[i].fr),y=find(edge[i].to);tmp[i].fr=x,tmp[i].to=y;if(x!=y)c[++num]=x,c[++num]=y;}sort(c+1,c+num+1); num=unique(c+1,c+num+1)-c-1;for(int i=1;i<=num;i++) fa2[i]=i;for(int i=l;i<=r;i++){if(tmp[i].fr==tmp[i].to) continue;int u=find(tmp[i].fr),v=find(tmp[i].to);if(u!=v) sum--,fa[u]=v;u=lower_bound(c+1,c+num+1,tmp[i].fr)-c; v=lower_bound(c+1,c+num+1,tmp[i].to)-c;a[u][u]++,a[u][v]--,a[v][v]++,a[v][u]--;int x=find2(u),y=find2(v);if(x!=y) fa2[x]=y;} for(int i=2;i<=num;i++)if(find2(i)!=find2(i-1)){int u=find2(i),v=find2(i-1);a[u][u]++,a[u][v]--,a[v][v]++,a[v][u]--;fa2[u]=v;}ans=1LL*ans*Matrix_tree(num)%mod;
}signed main(){n=rd(); m=rd();for(int i=1;i<=m;i++) edge[i].fr=rd(),edge[i].to=rd(),edge[i].w=rd();sort(edge+1,edge+m+1); int u,v; sum=n;for(int i=1;i<=n;i++) fa[i]=i;for(int i=1;i<=m;){int j=i; while(edge[j].w==edge[i].w) j++; j--;if(i==j){u=find(edge[i].fr),v=find(edge[i].to);if(u!=v) fa[u]=v,sum--;}else{memset(a,0,sizeof a); solve(i,j);}i=j+1;}if(sum>1) puts("0");else printf("%lld\n",ans);return 0;
}

矩阵树定理--luoguP4208 [JSOI2008]最小生成树计数相关推荐

  1. [XSY]Tree Ext(矩阵树定理,拉格朗日插值,最小生成树,二分)

    Tree Ext 这道题相当于把3道题合了起来. 要求修复的边中恰好有 k 条白边: 五颜六色的幻想乡(附拉格朗日插值法求多项式系数 ) + bzoj2654 tree(WQS二分 新科技get) 是 ...

  2. [P4455][CQOI2018]社交网络(矩阵树定理)

    关于矩阵树定理用于有向图生成树计数: ①内向树生成树计数.  A为邻接矩阵, D为出度矩阵.  C=D−A.  以root为根的内向生成树个数为C的余子式M[root,root]的行列式.  ②外向树 ...

  3. BZOJ1016 || 洛谷P4208 [JSOI2008]最小生成树计数【矩阵树定理】

    时空限制 1000ms / 128MB 题目描述 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则 ...

  4. 最小生成树、矩阵树定理、Prufer序列总结

    Kruskal算法 按边权排序,从小到大合并不在同一集合两点即可 Prim算法 每次加入一个到当前已选点集最近的点 P2619 [国家集训队]Tree I 考虑二分,每次给白边加上一个mid,通过这种 ...

  5. 基尔霍夫(kirchhoff)矩阵树定理

    引入问题   给n个点m条边的图,求该图的最小生成树个数. 定理内容   我们对这个图构造两个矩阵,分别是这个图的连通矩阵和度数矩阵.连通矩阵S1S1S1的第iii行第jjj列上的数字表示原无向图中编 ...

  6. 【学习笔记】矩阵树定理(Matrix-Tree)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 目录 一.矩阵树定理 二.常用定理 三.例题 1. Luogu P6178 [模板]Matrix-Tr ...

  7. 图论数学:矩阵树定理

    运用矩阵树定理进行生成树计数 给定一个n个点m条边的无向图,问生成树有多少种可能 直接套用矩阵树定理计算即可 矩阵树定理的描述如下: 首先读入无向图的邻接矩阵,u-v G[u][v]++ G[v][u ...

  8. bzoj1016 [JSOI2008]最小生成树计数

    1016: [JSOI2008]最小生成树计数 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 6032  Solved: 2452 [Submit][ ...

  9. 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点出发走遍所 ...

最新文章

  1. 7-22 堆栈模拟队列 (25 分)
  2. java 数据库提交,java.sql.Statement向数据库提交的语句不可以是SQL语句的()。
  3. Codeforces 698D Limak and Shooting Points (搜索)
  4. when click one item in table Select at least one column to perform the search
  5. unsigned char s1 : 2的用法
  6. 最佳实践|Spring Boot 应用如何快速接入 Prometheus 监控
  7. 作为一个程序员,CPU的这些硬核知识你必须会!
  8. C++ 与 php 的交互 之----- C++ 异步获取 网页文字内容,异步获取 php 的 echo 值。...
  9. PyTorch 1.0 中文官方教程:序列模型和LSTM网络
  10. seleniuim面试题1
  11. 一些推荐的深度学习、机器学习资料
  12. ubuntu 一张网卡绑定多个ip
  13. phpredis中文手册《redis中文手册》php版
  14. Neo4j 图数据库高级应用系列 / 服务器扩展指南 APOC 8.6 - 图生成 小世界模型
  15. idea自动更新IDE Eval Reset插件安装
  16. poj2069求最小外接球半径 模拟退火
  17. 罗振宇 知识就是力量之 怎样重新获得别人的信任
  18. Do it for success
  19. 如何使用万能地图下载器下载矢量路网
  20. ReportView报表控件使用方法

热门文章

  1. 梦想世界3手游服务器维护,梦想世界手游进不去 闪退及登录不上解决方法
  2. 基于Hadoop豆瓣电影数据分析(综合实验)
  3. web前端之百度首页仿写
  4. python halcon_HALCON高级篇:常用分类器及其特点
  5. anr用户无响应问题的解决
  6. 【vue-router源码】五、router.addRoute、router.removeRoute、router.hasRoute、router.getRoutes源码分析
  7. 计算机排版打字操作,五笔字型与计算机排版培训教程2版 第9章 打字与排版的首选—Word 2007.ppt...
  8. Chrome浏览器支持的时间格式
  9. 基于Docker搭建DzzOffice与OnlyOffice线上协同办公服务器
  10. 协议和服务器有什么区别,服务期协议是什么,劳动合同与服务期协议有什么区别?...