Description

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

Input

第一行包含两个数,n和m,其中1<=n<=100; 1<=m<=1000; 表示该无向图的节点数和边数。每个节点用1~n的整数编号。接下来的m行,每行包含两个整数:a, b, c,表示节点a, b之间的边的权值为c,其中1<=c<=1,000,000,000。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过10条。

Output

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

Sample Input

4 6

1 2 1

1 3 1

1 4 1

2 3 2

2 4 1

3 4 1

Sample Output

8

Solution

对于不同的MST方案,相同权值的边数总是一定。因此我们可以排序后先跑一次MST并离散权值,统计出每种权值被用了多少次,然后对于每种权值暴力枚举各条边是否使用,检查合法性以及使用边数是否等于原本所使用的,乘法原理一下即可,由于有撤销操作不能够压缩路径,因此建议采用启发式合并。

时间复杂度\(O(E \log_2 E + \Sigma 2^{cnt_{v}} * \log_{2} V)\)其中\(cnt_{v}\)表示权值v在MST中的使用次数。

Code

#include <stdio.h>
#include <algorithm>
#define MN 105
#define MM 1005
#define R register
#define mod 31011
inline int read(){
R int x; R bool f; R char c;
for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-');
for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0');
return f?-x:x;
}
int V,E,cnt,val[MM],x[MM],y[MM],rk[MM],l[MM],r[MM],v[MM],fa[MN],sz[MN],sum,ans=1,k;
inline bool cmp(int x,int y){return val[x]<val[y];}
inline int find(int x){return fa[x]==x?x:find(fa[x]);}
inline void swap(int &x,int &y){x^=y,y^=x,x^=y;}
inline void ins(int x,int y){
if (sz[x]<sz[y]) swap(x,y);
fa[y]=x;sz[x]+=sz[y];
}
inline void del(int x,int y){
if (fa[x]==y) swap(x,y);
fa[y]=y; sz[x]-=sz[y];
}
inline void dfs(int t,int no,int k){
if (no>r[t]){
sum+=(k==v[t]);
return;
}R int p=find(x[rk[no]]),q=find(y[rk[no]]);
if (p!=q){
ins(p,q);dfs(t,no+1,k+1);del(p,q);
}dfs(t,no+1,k);
}
int main(){
V=read(),E=read();for (R int i=1; i<=E; ++i) x[i]=read(),y[i]=read(),val[i]=read(),rk[i]=i;
std::sort(rk+1,rk+E+1,cmp);for (R int i=1; i<=V; ++i) fa[i]=i;
for (R int i=1; i<=E; ++i){
if (val[rk[i]]!=val[rk[i-1]]) {r[cnt]=i-1; if (k==V-1) break;l[++cnt]=i;}
R int p=find(x[rk[i]]),q=find(y[rk[i]]);
if (p!=q){ins(p,q);++v[cnt],++k;}
}if (!r[cnt]) r[cnt]=E;if (k!=V-1){puts("0");return 0;}for (R int i=1; i<=V; ++i) fa[i]=i;
for (R int i=1; i<=cnt; ++i){
sum=0;dfs(i,l[i],0);ans=ans*sum%mod;
for (R int j=l[i]; j<=r[i]; ++j){
R int p=find(x[rk[j]]),q=find(y[rk[j]]);
if (p!=q) ins(p,q);
}
}printf("%d\n",ans);
return 0;
}

【BZOJ1016】【JSOI2008】最小生成树计数的更多相关文章

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

    1016: [JSOI2008]最小生成树计数 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 3517  Solved: 1396[Submit][St ...

  2. bzoj1016: [JSOI2008]最小生成树计数(kruskal+dfs)

    1016: [JSOI2008]最小生成树计数 题目:传送门 题解: 神题神题%%% 据说最小生成树有两个神奇的定理: 1.权值相等的边在不同方案数中边数相等  就是说如果一种方案中权值为1的边有n条 ...

  3. BZOJ1016:[JSOI2008]最小生成树计数(最小生成树,DFS)

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

  4. [bzoj1016][JSOI2008]最小生成树计数 (Kruskal + Matrix Tree 定理)

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

  5. 【Matrix-tree定理】【并查集】【kruscal算法】bzoj1016 [JSOI2008]最小生成树计数

    题意:求一个图的最小生成树个数. 矩阵树定理:一张无向图的生成树个数 = (度数矩阵 - 邻接矩阵)的任意一个n-1主子式的值. 度数矩阵除了对角线上D[i][i]为i的度数(不计自环)外,其他位置是 ...

  6. [BZOJ1016][JSOI2008]最小生成树计数(结论题)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1016 分析: 首先有个性质:如果边集E.E'都可以表示一个图G的最小生成树(当然E和E ...

  7. [BZOJ1016] [JSOI2008] 最小生成树计数 (Kruskal)

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

  8. 【最小生成树】BZOJ1016: [JSOI2008]最小生成树计数

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

  9. 2018.09.24 bzoj1016: [JSOI2008]最小生成树计数(并查集+搜索)

    传送门 正解是并查集+矩阵树定理. 但由于数据范围小搜索也可以过. 我们需要知道最小生成树的两个性质: 不同的最小生成树中,每种权值的边出现的个数是确定的 不同的生成树中,某一种权值的边连接完成后,形 ...

  10. [BZOJ1016][JSOI2008]最小生成树计数 最小生成树 搜索

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1016 做这道题之前需要知道一些结论,同一个图的最小生成树中相同权值的边的个数是不会变的,如 ...

随机推荐

  1. Beta冲刺置顶随笔

    项目名称:城市安全风险管控系统 小组成员: 张梨贤.林静.周静平.黄腾飞 Beta冲刺随笔 Beta预备 Beta冲刺Day1 Beta冲刺Day2 Beta冲刺Day3 Beta冲刺Day4 Bet ...

  2. 一个C&C++程序的生命历程

    翻了好多博客,内容星星点点,没找到我想要的,现在吸取大神精华,加上本人拙见,总结如下: 一个C或C++程序从你开始编写,到结束,整个过程,都做了些什么,请看下文: 先看大体的过程:看图: 我在这里主要 ...

  3. 基础篇 - SQL 的约束

    基础篇 - SQL 的约束       约束 一.实验简介 约束是一种限制,它通过对表的行或列的数据做出限制,来确保表的数据的完整性.唯一性.本节实验将在实践操作中熟悉 MySQL 中的几种约束. 二 ...

  4. Excel+DDT数据驱动实例

    一.首先安装dtt模块 数据驱动原理 1.测试数据为多个字典的list类型 2.测试类前加修饰@ddt.ddt 3.case前加修饰@ddt.data() 4.运行后用例会自动加载成N个单独的用例 二 ...

  5. Win7添加php环境变量.

    1) "我的电脑"右键"属性"->高级系统设置->环境变量->系统变量->Path->编辑 2) 将PHP的执行路径的目录&quo ...

  6. Linq GroupJoin

    static void Main(string[] args) { List<Person> persons = new List<Person> { }, }, }; Lis ...

  7. 解决编写的 html 乱码问题

  8. Linux下的Shell编程(2)环境变量和局部变量

    Shell Script是一种弱类型语言,使用变量的时候无需首先声明其类型. 局部变量在本地数据区分配内存进行存储,这个变量归当前的Shell所有,任何子进 程都不能访问本地变量.这些变量与环境变量不 ...

  9. python爬虫——分析天猫iphonX的销售数据

    01.引言 这篇文章是我最近刚做的一个项目,会带领大家使用多种技术实现一个非常有趣的项目,该项目是关于苹果机(iphoneX)的销售数据分析,是网络爬虫和数据分析的综合应用项目.本项目会分别从天猫和京 ...

  10. R数据分析 第一篇:温习概率论

    概率论是人们在长期实践中发现的理论,是客观存在的.自然界和社会上发生的现象是多种多样的,有一类现象,在一定条件下必然发生,称作确定性现象,而概率论研究的现象是不确定性现象,嗯嗯,醒醒,概率论研究的对象 ...