BZOJ1016 || 洛谷P4208 [JSOI2008]最小生成树计数【矩阵树定理】
时空限制 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]最小生成树计数【矩阵树定理】相关推荐
- 洛谷 P4208 [JSOI2008]最小生成树计数 矩阵树定理
题目描述 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的).由于不同的 ...
- 洛谷4455 [CQOI2018]社交网络 (有向图矩阵树定理)(学习笔记)
sro_ptx_orz qwq算是一个套路的记录 对于一个有向图来说 如果你要求一个外向生成树的话,那么如果存在一个\(u\rightarrow v\)的边 那么\(a[u][v]--,a[v][v] ...
- 最小生成树、矩阵树定理、Prufer序列总结
Kruskal算法 按边权排序,从小到大合并不在同一集合两点即可 Prim算法 每次加入一个到当前已选点集最近的点 P2619 [国家集训队]Tree I 考虑二分,每次给白边加上一个mid,通过这种 ...
- P4208 [JSOI2008]最小生成树计数
传送门 首先最小生成树有这么两个性质 1.不同的最小生成树中,每种权值的边出现的个数是确定的2.不同的生成树中,某一种权值的边连接完成后,形成的联通块状态是一样的 打个比方,以下图为例(图是网上的) ...
- 【BZOJ1016】【Luogu P4208】 [JSOI2008]最小生成树计数 最小生成树,矩阵树定理
蛮不错的一道题,遗憾就遗憾在数据范围会导致暴力轻松跑过. 最小生成树的两个性质: 不同的最小生成树,相同权值使用的边数一定相同. 不同的最小生成树,将其都去掉同一个权值的所有边,其连通性一致. 这样我 ...
- bzoj1016 [JSOI2008]最小生成树计数
1016: [JSOI2008]最小生成树计数 Time Limit: 1 Sec Memory Limit: 162 MB Submit: 6032 Solved: 2452 [Submit][ ...
- BZOJ 1016: [JSOI2008]最小生成树计数( kruskal + dfs )
不同最小生成树中权值相同的边数量是一定的, 而且他们对连通性的贡献是一样的.对权值相同的边放在一起(至多10), 暴搜他们有多少种方案, 然后乘法原理. ----------------------- ...
- 洛谷 p1197 [JSOI2008]星球大战(并查集)
洛谷 P1197 [JSOI2008]星球大战 题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系.某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了 ...
- 洛谷P1061 Jam的计数法 数学
洛谷P1061 Jam的计数法 数学 已知一个字符串 其 均有 s--t构成 且字符串要求 s[ i ]<s[ j ] i < j 已知一个字符串 求按字典序排列 的后5个字符串 1. ...
最新文章
- Activity和Service的生命周期-----Activity学习笔记(一)
- Android单击、长按获取当前触点坐标下(TextView)文字字符
- (vue基础试炼_02)使用vue.js实现隔2秒显示不同内容
- 信息学奥赛C++语言:重组
- 袁大头 如何辨别假货
- 湖北省大数据发展行动计划(2016-2020年)
- win8 32位系统上如何运行校园翼讯客户端
- Java中动态代理实现原理深究
- Backspace删除键不能够使用的解决办法
- jstl fn 函数
- 小码哥C++_面向对象
- python requests 异步调用_python - 如何使用requests_html异步获取()URL列表? - 堆栈内存溢出...
- 网格交易法以及在数字货币中基于Python的量化实现
- Windows改装成Linux,Windows系统改装成Linux系统
- Livox激光MID-360使用与fast-lio2激光SLAM建图
- 无锁队列与有锁队列性能比较
- 计算机运筹学pdf,计算题专题七运筹学计算上典型考题思路讲解.pdf
- 逻辑漏洞原理与实践练习题
- uniapp开发微信小程序实现语音识别,使用微信同声传译插件,
- Ubuntu22.04下安装OpenFOAM
热门文章
- MPC5748g基于源码实现ENET-PING实验(编译+调试)
- 2015级移动本面向对象课程主页
- 创维30周年庆典举行,中国制造业标杆向千亿目标加速冲刺
- 毕业旅行 | 用一场纽约5日游告别难忘青葱岁月
- 电脑蓝屏黑屏无法开机.BIOS更新.进不去系统只能重装?驱动人生解决方案
- 大唐杯学习笔记(1)—— 5G网络架构与组网部署
- 行人重识别的挑战 与 最新进展 (35页PPT整理)
- 轻松实现网页中通过链接跳转到QQ聊天界面,通过链接加QQ群,自动打开聊天对话框等等,包含电脑版和手机版的实现,示例部分Android和iOS的代码
- ltv价值 应用_手游LTV(用户终生价值)计算公式
- 程序员的工资是不是被高估了?