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. Flask 蓝图(Blueprint)

    蓝图使用起来就像应用当中的子应用一样,可以有自己的模板,静态目录,有自己的视图函数和URL规则,蓝图之间互相不影响.但是它们又属于应用中,可以共享应用的配置.对于大型应用来说,我们可以通过添加蓝图来扩 ...

  2. TF中conv2d和kernel_initializer方法

    conv2d中的padding 在使用TF搭建CNN的过程中,卷积的操作如下 convolution = tf.nn.conv2d(X, filters, strides=[1,2,2,1], pad ...

  3. Python内置函数(11)——complex

    英文文档: class complex([real[, imag]]) Return a complex number with the value real + imag*1j or convert ...

  4. 从感知机到 SVM,再到深度学习(一)

        在上篇博客中提到,如果想要拟合一些空间中的点,可以用最小二乘法,最小二乘法其实是以样例点和理论值之间的误差最小作为目标.那么换个场景,如果有两类不同的点,而我们不想要拟合这些点,而是想找到一条 ...

  5. C# word文档转换成PDF格式文档

    最近用到一个功能word转pdf,有个方法不错,挺方便的,直接调用即可,记录下 方法:ConvertWordToPdf(string sourcePath, string targetPath) so ...

  6. ssh整合之六管理我们的配置文件

    1.我们的ssh搭建已经搭建好了,之前是纯xml方式,而且我们的配置文件,是一个框架一个配置文件.这样的话,配置文件中的内容就会很多,这样以后修改起来也会很麻烦,因        此,我们尝试着把这些 ...

  7. Python之面向对象三

    面向对象的三大特性: 多态 多态指的是一类事物有多种形态.Python3天生支持多态. 动物有多种形态:人,狗,猪 import abc class Animal(metaclass=abc.ABCM ...

  8. Python之IO模型

    IO模型介绍 为了更好地了解IO模型,我们需要事先回顾下:同步.异步.阻塞.非阻塞 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞 ...

  9. 深度理解DOM拷贝clone()

    克隆节点是DOM的常见操作,jQuery提供一个clone方法,专门用于处理dom的克隆: .clone()方法深度 复制所有匹配的元素集合,包括所有匹配元素.匹配元素的下级元素.文字节点. clon ...

  10. 对return函数的认识

    例1: def funOut(): def funIn(): print('宾果!你成功访问到我啦!') return funIn() #注意这里return的是funIn()即是一个函数 funOu ...