BZOJ.1016.[JSOI2008]最小生成树计数(Matrix Tree定理 Kruskal)
最小生成树有两个性质:
1.在不同的MST中某种权值的边出现的次数是一定的。
2.在不同的MST中,连接完某种权值的边后,形成的连通块的状态是一样的。
\(Solution1\)
由这两个性质,可以先求一个MST,再枚举每一组边(权值相同的看做一组边),对每组边DFS(\(O(2^{10})\)),若某种方案连通性同MST相同(记录连通块个数即可)。则sum++。
最后根据乘法原理,最后的答案即为所有sum相乘。
\(Solution2\)
容易想到MatrixTree定理。
按边权从小到大处理每一组边,在加入这组边之前,之前的边会构成一些连通块,而这组边会一定会将某些连通块连在一起,如下图(我也不知道这图到底是哪的了):

把之前形成的每个连通块看做一个点,这样又成了一个生成树计数,生成树个数即为该种权值的边的方案数。如下图:

根据乘法原理,我们只要计算出每组边的这个方案,再乘起来就行了。
//920kb 68ms
#include <cstdio>
#include <cctype>
#include <vector>
#include <cstring>
#include <algorithm>
#define gc() getchar()
#define mod (31011)
const int N=102,M=1002;
int n,m,A[N][N],tmp[N][N],fa[N],bel[N],Ans;
bool vis[N];
std::vector<int> v[N];
struct Edge{
int fr,to,val;
bool operator <(const Edge &a)const{
return val<a.val;
}
}e[M];
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
int Get_fa(int x,int *f){//两个并查集,一个维护MST中的连通性,一个维护所属连通块。
return x==f[x]?x:f[x]=Get_fa(f[x],f);
}
void Gauss(int n)
{
for(int i=1; i<n; ++i)
for(int j=1; j<n; ++j) (A[i][j]+=mod)%=mod;//!
bool f=0;
for(int j=1; j<n; ++j)
{
for(int i=j+1; i<n; ++i)
while(A[i][j])
{
int t=A[j][j]/A[i][j];
for(int k=j; k<n; ++k) A[j][k]=(A[j][k]-t*A[i][k]%mod+mod)%mod;
for(int k=j; k<n; ++k) std::swap(A[i][k],A[j][k]);
f^=1;
}
if(!A[j][j]) {Ans=0; break;}
Ans=Ans*A[j][j]%mod;
}
if(f) Ans=mod-Ans;//!
}
void Calc()
{
for(int i=1; i<=n; ++i)
if(vis[i]) v[Get_fa(i,bel)].push_back(i),vis[i]=0;//处理出每个连通块所含的点(原先连通块的代表元素)。
for(int x=1; x<=n; ++x)
if(v[x].size()>1)
{
memset(A,0,sizeof A);
for(int i=0,lim=v[x].size(); i<lim; ++i)
for(int a=v[x][i],b,j=i+1; j<lim; ++j)
{
b=v[x][j];
if(tmp[a][b]){//tmp[][]作为边矩阵可以不清空,因为这俩连通块不会再同时出现了。
A[i][j]=A[j][i]=-tmp[a][b];
A[i][i]+=tmp[a][b], A[j][j]+=tmp[a][b];
}
}
Gauss(v[x].size());
}
for(int i=1; i<=n; ++i)
v[i].clear(), bel[i]=fa[i]=Get_fa(i,bel);//计算完某种边后把同一连通块的缩起来。
}
int main()
{
n=read(),m=read();
for(int i=1; i<=m; ++i) e[i].fr=read(),e[i].to=read(),e[i].val=read();
std::sort(e+1,e+1+m);
for(int i=1; i<=n; ++i) fa[i]=bel[i]=i;
e[0].val=e[1].val, Ans=1;
for(int r1,r2,i=1; i<=m; ++i)
{
if(e[i].val!=e[i-1].val) Calc();
r1=Get_fa(e[i].fr,fa), r2=Get_fa(e[i].to,fa);
if(r1==r2) continue;
// fa[r1]=r2;//暂时先不连接。
vis[r1]=vis[r2]=1;
++tmp[r1][r2], ++tmp[r2][r1];//, ++tmp[r1][r1], ++tmp[r2][r2];//点的度数矩阵可以之后根据边处理,tmp[][]用来做边矩阵。最好这样,可以不清空。
bel[Get_fa(e[i].fr,bel)]=Get_fa(e[i].to,bel);//统计出每个连通块。
}
Calc();//the last edge
for(int i=1; i<n; ++i)
if(bel[i]!=bel[i+1]) {Ans=0; break;}
printf("%d",Ans);
return 0;
}
BZOJ.1016.[JSOI2008]最小生成树计数(Matrix Tree定理 Kruskal)的更多相关文章
- bzoj 1016 [JSOI2008]最小生成树计数——matrix tree(相同权值的边为阶段缩点)(码力)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1016 就是缩点,每次相同权值的边构成的联通块求一下matrix tree.注意gauss里的 ...
- BZOJ 1016: [JSOI2008]最小生成树计数( kruskal + dfs )
不同最小生成树中权值相同的边数量是一定的, 而且他们对连通性的贡献是一样的.对权值相同的边放在一起(至多10), 暴搜他们有多少种方案, 然后乘法原理. ----------------------- ...
- [BZOJ 1016] [JSOI2008] 最小生成树计数 【DFS】
题目链接:BZOJ - 1016 题目分析 最小生成树的两个性质: 同一个图的最小生成树,满足: 1)同一种权值的边的个数相等 2)用Kruscal按照从小到大,处理完某一种权值的所有边后,图的连通性 ...
- [BZOJ]1016 JSOI2008 最小生成树计数
最小生成树计数 题目描述 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同 ...
- BZOJ 1016 [JSOI2008]最小生成树计数 ——Matrix-Tree定理
考虑从小往大加边,然后把所有联通块的生成树个数计算出来. 然后把他们缩成一个点,继续添加下一组. 最后乘法原理即可. 写起来很恶心 #include <queue> #include &l ...
- bzoj 1016: [JSOI2008]最小生成树计数【dfs+克鲁斯卡尔】
有一个性质就是组成最小生成树总边权值的若干边权总是相等的 这意味着按边权排序后在权值相同的一段区间内的边能被选入最小生成树的条数是固定的 所以先随便求一个最小生成树,把每段的入选边数记录下来 然后对于 ...
- 【BZOJ 1016】 1016: [JSOI2008]最小生成树计数 (DFS|矩阵树定理)
1016: [JSOI2008]最小生成树计数 Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树 ...
- 1016: [JSOI2008]最小生成树计数
1016: [JSOI2008]最小生成树计数 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 6200 Solved: 2518[Submit][St ...
- @总结 - 7@ 生成树计数 —— matrix - tree 定理(矩阵树定理)与 prüfer 序列
目录 @0 - 参考资料@ @0.5 - 你所需要了解的线性代数知识@ @1 - 矩阵树定理主体@ @证明 part - 1@ @证明 part - 2@ @证明 part - 3@ @证明 part ...
随机推荐
- python f-string
文章目录 1. 主要内容 1.1. 旧时代的格式化字符串 1.1.1. Option #1: %-formatting 1.1.2. 怎样使用 %-formatting 1.1.3. 为什么 %-fo ...
- log4j2使用入门(二)——与不同日志框架的适配
在之前博客中已经指出log4j2可以与不同的日志框架进行适配,这里举一些实际应用进行说明: 1.比如我们在项目中使用了log4j2作为日志器,使用了log4j-api2.6.2.jar和log4j-c ...
- springboot系列十五、springboot集成PageHelper
一.介绍 项目中经常会遇到分页,PageHelper为我们解决了这个问题.本质上实现了Mybatis的拦截器,作了分页处理. 二.配置PageHelper 1.引入依赖 pagehelper-spri ...
- ES系列十三、Elasticsearch Suggester API(自动补全)
1.概念 1.补全api主要分为四类 Term Suggester(纠错补全,输入错误的情况下补全正确的单词) Phrase Suggester(自动补全短语,输入一个单词补全整个短语) Comple ...
- expdp和impdp导入和导出数据
一 关于expdp和impdp 使用EXPDP和IMPDP时应该注意的事项:EXP和IMP是客户端工具程序,它们既可以在客户端使用,也可以在服务端使用.EXPDP和IMPDP是服务端的工具程 ...
- SharePoint 2010 使用沙盒解决方案隐藏页面中的”元素”
起因: 一朋友问我如何隐藏SharePoint 2010中"回收站"和"所有网站内容".我告诉他需要写点css,然后他就蒙圈了(他是英文专业). 解决方案: 一 ...
- softlab对接Jenkins工程
在Softlab上对接jenkins工程,必须先在自己的jenkins环境上配置好任务. 1.登陆到jenkins首页,比如http://10.179.175.53:8080/jenkins/ 2.点 ...
- @PathVariable和@RequestParam
@PathVariable 当使用@RequestMapping URI template 样式映射时, 即 someUrl/{paramId}, 这时的paramId可通过 @Pathvariabl ...
- springboot:session集中存储到redis
1.在web工程的基础上,在pom.xml中添加: <dependency> <groupId>org.springframework.boot</groupId> ...
- Android天气预报
Android天气预报 1.指定 WebService 的命名空间和调用方法import org.ksoap2.serialization.SoapObject;private static fina ...