时空限制 1000ms / 128MB

题目描述

现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生成树可能很多,所以你只需要输出方案数对31011的模就可以了。

输入格式:

第一行包含两个数,n和m,其中1<=n<=100; 1<=m<=1000; 表示该无向图的节点数和边数。每个节点用1~n的整数编号。

接下来的m行,每行包含两个整数:a, b, c,表示节点a, b之间的边的权值为c,其中1<=c<=1,000,000,000。

数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过10条。

输出格式:

输出不同的最小生成树有多少个。你只需要输出数量对31011的模就可以了。

说明

说明 1<=n<=100; 1<=m<=1000;1≤ci≤1091\leq c_i\leq 10^91≤ci​≤109


题目分析

首先最小生成树有这样的性质

若A,B为图G的不同最小生成树
设它们的边从小到大依次为wa1,wa2…wan−1w_{a_1},w_{a_2}\dots w_{a_{n-1}}wa1​​,wa2​​…wan−1​​和wb1,wb2…wbn−1w_{b_1},w_{b_2}\dots w_{b_{n-1}}wb1​​,wb2​​…wbn−1​​
这些边的条数分别为ka1,ka2…kan−1k_{a_1},k_{a_2}\dots k_{a_{n-1}}ka1​​,ka2​​…kan−1​​和kb1,kb2…kbn−1k_{b_1},k_{b_2}\dots k_{b_{n-1}}kb1​​,kb2​​…kbn−1​​
那么有wai=wbiw_{a_i}=w_{b_i}wai​​=wbi​​且kai=kbik_{a_i}=k_{b_i}kai​​=kbi​​

即所有最小生成树的边权出现情况都相同

假设当前已有一个最小生成树,若删去其中所有边权为wiw_iwi​的边,图会变成若干个森林
根据上述性质,此时在原图中所有权值为wiw_iwi​的边中取kik_iki​条,若能组成生成树,则一定是最小的
将此时的合法选择方案数记为cic_ici​,那么根据乘法原理答案∏ci\prod c_i∏ci​

所以对于本题,先用Kruskal求出原图的一个最小生成树,记录所有树边和出现过的权值
遍历每个不同权值wiw_iwi​,连接树边中所有权值不为wiw_iwi​的边,将每个联通快缩点
用原图中所有权值为wiw_iwi​的边构造基尔霍夫矩阵,应用矩阵树定理求出cic_ici​
乘法原理累乘cic_ici​即可

据说这题搜索也能过???

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long lt;int read()
{int f=1,x=0;char ss=getchar();while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}return f*x;
}const int mod=31011;
const int maxn=210;
int n,m;
struct node{int u,v,dis;}E[maxn*10],T[maxn];
int fa[maxn],rem[maxn],tot;
int col[maxn],coln;
int a[maxn][maxn];bool cmp(node a,node b){ return a.dis<b.dis;}int find(int x)
{if(x==fa[x]) return x;else return fa[x]=find(fa[x]);
}int kruskal()
{sort(E+1,E+1+m,cmp); int cnt=0;for(int i=1;i<=n;++i) fa[i]=i;for(int i=1;i<=m;++i){int u=E[i].u,v=E[i].v;int fu=find(E[i].u),fv=find(E[i].v);if(fu!=fv){fa[fu]=fv; T[++cnt]=E[i];if(E[i].dis!=rem[tot]) rem[++tot]=E[i].dis;if(cnt==n-1) return 1;}}return 0;
}void addE(int val)
{for(int i=1;i<=n;++i) fa[i]=i;for(int i=1;i<n;++i)if(T[i].dis!=val){int fu=find(T[i].u),fv=find(T[i].v);if(fu!=fv) fa[fu]=fv;}
}void qblock()
{coln=0;for(int i=1;i<=n;++i)if(find(i)==i) col[i]=++coln;for(int i=1;i<=n;++i)col[i]=col[find(i)];
}void build(int val)
{memset(a,0,sizeof(a));for(int i=1;i<=m;++i)if(E[i].dis==val){int u=col[E[i].u],v=col[E[i].v];a[u][u]++; a[v][v]++; a[u][v]--; a[v][u]--;}
}int gauss(int lim)
{int res=1;for(int i=1;i<lim;++i){for(int j=i+1;j<lim;++j)while(a[j][i]){int t=a[i][i]/a[j][i];for(int k=i;k<lim;++k)a[i][k]=(a[i][k]-t*a[j][k]+mod)%mod;swap(a[j],a[i]);res=-res;}res=(res*a[i][i])%mod;}return (res+mod)%mod;
}int main()
{   n=read();m=read();for(int i=1;i<=m;++i)E[i].u=read(),E[i].v=read(),E[i].dis=read();if(!kruskal()){ printf("0"); return 0;}int ans=1;for(int i=1;i<=tot;++i){addE(rem[i]); qblock(); build(rem[i]);ans=ans*gauss(coln)%mod;}printf("%d",(ans+mod)%mod);return 0;
}

BZOJ1016 || 洛谷P4208 [JSOI2008]最小生成树计数【矩阵树定理】相关推荐

  1. 洛谷 P4208 [JSOI2008]最小生成树计数 矩阵树定理

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

  2. 洛谷4455 [CQOI2018]社交网络 (有向图矩阵树定理)(学习笔记)

    sro_ptx_orz qwq算是一个套路的记录 对于一个有向图来说 如果你要求一个外向生成树的话,那么如果存在一个\(u\rightarrow v\)的边 那么\(a[u][v]--,a[v][v] ...

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

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

  4. P4208 [JSOI2008]最小生成树计数

    传送门 首先最小生成树有这么两个性质 1.不同的最小生成树中,每种权值的边出现的个数是确定的2.不同的生成树中,某一种权值的边连接完成后,形成的联通块状态是一样的 打个比方,以下图为例(图是网上的) ...

  5. 【BZOJ1016】【Luogu P4208】 [JSOI2008]最小生成树计数 最小生成树,矩阵树定理

    蛮不错的一道题,遗憾就遗憾在数据范围会导致暴力轻松跑过. 最小生成树的两个性质: 不同的最小生成树,相同权值使用的边数一定相同. 不同的最小生成树,将其都去掉同一个权值的所有边,其连通性一致. 这样我 ...

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

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

  7. BZOJ 1016: [JSOI2008]最小生成树计数( kruskal + dfs )

    不同最小生成树中权值相同的边数量是一定的, 而且他们对连通性的贡献是一样的.对权值相同的边放在一起(至多10), 暴搜他们有多少种方案, 然后乘法原理. ----------------------- ...

  8. 洛谷 p1197 [JSOI2008]星球大战(并查集)

    洛谷 P1197 [JSOI2008]星球大战 题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系.某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了 ...

  9. 洛谷P1061 Jam的计数法 数学

    洛谷P1061 Jam的计数法 数学  已知一个字符串 其 均有 s--t构成 且字符串要求 s[ i ]<s[ j ] i < j 已知一个字符串 求按字典序排列 的后5个字符串 1. ...

最新文章

  1. Activity和Service的生命周期-----Activity学习笔记(一)
  2. Android单击、长按获取当前触点坐标下(TextView)文字字符
  3. (vue基础试炼_02)使用vue.js实现隔2秒显示不同内容
  4. 信息学奥赛C++语言:重组
  5. 袁大头 如何辨别假货
  6. 湖北省大数据发展行动计划(2016-2020年)
  7. win8 32位系统上如何运行校园翼讯客户端
  8. Java中动态代理实现原理深究
  9. Backspace删除键不能够使用的解决办法
  10. jstl fn 函数
  11. 小码哥C++_面向对象
  12. python requests 异步调用_python - 如何使用requests_html异步获取()URL列表? - 堆栈内存溢出...
  13. 网格交易法以及在数字货币中基于Python的量化实现
  14. Windows改装成Linux,Windows系统改装成Linux系统
  15. Livox激光MID-360使用与fast-lio2激光SLAM建图
  16. 无锁队列与有锁队列性能比较
  17. 计算机运筹学pdf,计算题专题七运筹学计算上典型考题思路讲解.pdf
  18. 逻辑漏洞原理与实践练习题
  19. uniapp开发微信小程序实现语音识别,使用微信同声传译插件,
  20. Ubuntu22.04下安装OpenFOAM

热门文章

  1. MPC5748g基于源码实现ENET-PING实验(编译+调试)
  2. 2015级移动本面向对象课程主页
  3. 创维30周年庆典举行,中国制造业标杆向千亿目标加速冲刺
  4. 毕业旅行 | 用一场纽约5日游告别难忘青葱岁月
  5. 电脑蓝屏黑屏无法开机.BIOS更新.进不去系统只能重装?驱动人生解决方案
  6. 大唐杯学习笔记(1)—— 5G网络架构与组网部署
  7. 行人重识别的挑战 与 最新进展 (35页PPT整理)
  8. 轻松实现网页中通过链接跳转到QQ聊天界面,通过链接加QQ群,自动打开聊天对话框等等,包含电脑版和手机版的实现,示例部分Android和iOS的代码
  9. ltv价值 应用_手游LTV(用户终生价值)计算公式
  10. 程序员的工资是不是被高估了?