[BZOJ1543] 生成树计数 (Kruskal)

Description

  给定一个连通的带边权的图(允许自环和重边),求不同的最小生成树个数。两个生成树不同当它们所用的边的序号不同,换句话说,重边算多次。

Input

  第一行n,m,表示点数和边数(1<=n<=50000,1<=m<=100000) 下接m行,每行3个数k1,k2,w,表示k1和k2之间有一条权值为w 的边。

Output

  仅一行一个数:生成树个数 mod 1000003(质数)

Sample Input

3 5
1 2 6
1 2 6
2 3 6
3 1 6
3 3 8

Sample Output

5

  注:不会存在5条及5条以上的边,他们的边权是相同的。
  样例解释:
  5棵生成树分别如下(边按输入顺序标号):
  (1,3) (2,3) (1,4) (2,4) (3,4)
  5号边是自环。

HINT

Source

  HNOI2009集训Day3

Solution

  同$BZOJ1016$,感觉如果第一页那题能过,这题也能过。题解依然是我写的。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 struct edge
 4 {
 5     int u, v, w, x;
 6     inline bool operator< (const edge &rhs) const
 7     {
 8         return x < rhs.x;
 9     }
10 }e[100005];
11 struct count
12 {
13     int l, r, use;
14 }g[100005];
15 int n, m, fa[50005], siz[50005];
16
17 int getfa(int x)
18 {
19     return fa[x] == x ? x : getfa(fa[x]);
20 }
21
22 void link(int u, int v)
23 {
24     if(siz[u] > siz[v]) fa[v] = u, siz[u] += siz[v];
25     else fa[u] = v, siz[v] += siz[u];
26 }
27
28 bool Kruskal()
29 {
30     int cnt = 0, u, v;
31     for(int i = 1; i <= m; ++i)
32     {
33         u = getfa(e[i].u), v = getfa(e[i].v);
34         if(u != v)
35         {
36             link(u, v);
37             ++g[e[i].w].use;
38             if(++cnt == n - 1) return true;
39         }
40     }
41     return false;
42 }
43
44 int DFS(int w, int i, int k)
45 {
46     if(k == g[w].use) return 1;
47     if(i > g[w].r) return 0;
48     int ans = 0, u = getfa(e[i].u), v = getfa(e[i].v);
49     if(u != v)
50     {
51         link(u, v);
52         ans = DFS(w, i + 1, k + 1);
53         fa[u] = u, fa[v] = v;
54     }
55     return ans + DFS(w, i + 1, k);
56 }
57
58 int main()
59 {
60     int u, v, w, ans;
61     cin >> n >> m;
62     for(int i = 1; i <= n; ++i)
63         fa[i] = i, siz[i] = 1;
64     for(int i = 1; i <= m; ++i)
65     {
66         cin >> u >> v >> w;
67         e[i] = (edge){u, v, 0, w};
68     }
69     sort(e + 1, e + m + 1);
70     w = 0;
71     for(int i = 1; i <= m; ++i)
72         if(e[i].x == e[i - 1].x) e[i].w = w;
73         else
74         {
75             g[w].r = i - 1;
76             e[i].w = ++w;
77             g[w].l = i;
78         }
79     g[w].r = m;
80     ans = Kruskal();
81     for(int i = 1; i <= n; ++i)
82         fa[i] = i, siz[i] = 1;
83     for(int i = 1; i <= w; ++i)
84     {
85         ans = ans * DFS(i, g[i].l, 0) % 1000003;
86         for(int j = g[i].l; j <= g[i].r; ++j)
87         {
88             u = getfa(e[j].u), v = getfa(e[j].v);
89             if(u != v) link(u, v);
90         }
91     }
92     cout << ans << endl;
93     return 0;
94 }

时间: 2025-01-11 00:34:38

[BZOJ1543] 生成树计数 (Kruskal)的相关文章

生成树计数

生成树计数就是统计一张图中一共有多少种构造生成树的方案. 大概要用到组合数学等等的数学知识. 以下内容均来自NOI2007国家集训队论文 周冬 <生成树的计数及其应用>: ------------------------- Matrix-Tree定理(Kirchhoff矩阵-树定理).Matrix-Tree定理是解决生成树计数问题最有力的武器之一.它首先于1847年被Kirchhoff证明.在介绍定理之前,我们首先明确几个概念: 1.G的度数矩阵D[G]是一个n*n的矩阵,并且满足:当i≠j时

kuangbin带你飞 生成树专题 : 次小生成树; 最小树形图;生成树计数

第一个部分 前4题 次小生成树 算法:首先如果生成了最小生成树,那么这些树上的所有的边都进行标记.标记为树边. 接下来进行枚举,枚举任意一条不在MST上的边,如果加入这条边,那么肯定会在这棵树上形成一个环,如果还要维护处树的特点 那么就要在这个环上删去一条边,这样他还是树,删掉的边显然是这条链上权值最大边更可能形成次小生成树.那么就有2中方法可以做. 第一种PRIM在prim时候直接可以做出这个从I到J的链上权值最大的值MAX[i][j]; 同时可以用kruskal同样方式标记树边,然后DFS跑

生成树计数 Matrix-Tree 定理

一直都知道要用Matrix-Tree定理来解决生成树计数问题,但是拖到今天才来学.博主数学不好也只能跟着各位大佬博客学一下它的应用以及会做题,证明实在是不会. 推荐博客https://blog.csdn.net/u011815404/article/details/89091011(Matrix-Tree定理) https://blog.csdn.net/u011815404/article/details/99679527(写得无敌好的生成树计数了) 那么比较常见的生成树计数问题就三种:①生成

bzoj1002 生成树计数 找规律

这道题第一眼是生成树计数,n是100,是可以用O(n^3)的求基尔霍夫矩阵的n-1阶的子矩阵的行列式求解的,但是题目中并没有说取模之类的话,就不好办了. 用高精度?有分数出现. 用辗转相除的思想,让它不出现分数.但过程中会出现负数,高精度处理负数太麻烦. 用Python打表?好吧,Python还不熟,写不出来..... 所以,如果这道题我考场上遇到,最多用double骗到n<=20的情况的部分分. 最终只能求助于题解了... 好像是通过观察行列式的特点,推导出关于答案f(n)的递推式(f(n)=

Uva 10766 Organising the Organisation (Matrix_tree 生成树计数)

题目描述: 一个由n个部门组成的公司现在需要分层,但是由于员工间的一些小小矛盾,使得他们并不愿意做上下级,问在满足他们要求以后有多少种分层的方案数? 解题思路: 生成树计数模板题,建立Kirchhoff矩阵,利用Matrix_tree定理求解. Kirchhoff矩阵:假设G为n*n矩阵,C为G的入度矩阵(i==j时,C[i][j]等于i的入度;i!=j时,C[i][j]等于零),A为G的邻接矩阵,那么就有Kirchhoff矩阵等于C-A. Matrix_tree定理:G的不同生成树的个数等于其

SPOJ104 Highways,生成树计数

高速公路(SPOJ104 Highways) 一个有n座城市的组成国家,城市1至n编号,其中一些城市之间可以修建高速公路.现在,需要有选择的修建一些高速公路,从而组成一个交通网络.你的任务是计算有多少种方案,使得任意两座城市之间恰好只有一条路径? 数据规模:1≤n≤12. 生成树计数 算法步骤: 1. 构建拉普拉斯矩阵 Matrix[i][j] = degree(i) , i==j -1,i-j有边 0,其他情况 2. 去掉第r行,第r列(r任意) 3. 计算矩阵的行列式 #include <m

bzoj 1005: [HNOI2008]明明的烦恼 prufer编号&amp;&amp;生成树计数

1005: [HNOI2008]明明的烦恼 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 2248  Solved: 898[Submit][Status] Description 自从明明学了树的结构,就对奇怪的树产生了兴趣...... 给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树? Input 第一行为N(0 < N < = 1000),接下来N行,第i+1行给出第i个节点的度数Di,如果对度

生成树计数模板

#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int N=55; typedef long long LL; int D[N][N]; LL C[N][N];//Kirchhoff矩阵 LL Det(LL a[][N],int n)//生成树计数:Matrix-

【生成树计数】专题总结

在CTSC和APIO上好像经常听到生成树计数这东西 于是就去看了下论文 蒟蒻表示看不懂证n明orz 反正懂用就行了.. 生成树计数 生成树计数就是给出一种n个点的无向图G 求这n个点的生成树个数 G的度数矩阵d[i][j] 当i≠j时d[i][j]=0 否则等于i点的度数 G的邻接矩阵a[i][j] a[i][j]=i.j间的边的个数(能有重边) Kirchhoff矩阵 c[i][j]=d[i][j]-a[i][j] Kirchhoff矩阵的n-1阶主子式的行列式的值的绝对值即为生成树的个数 n