Bzoj1016 最小生成树计数

Time Limit: 1000MS   Memory Limit: 165888KB   64bit IO Format: %lld & %llu

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,0
00。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过10条。

Output

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

Sample Input

4 61 2 11 3 11 4 12 3 22 4 13 4 1

Sample Output

8

Hint

Source

JSOI2008

kruskal算法的改版。

首先按照kruskal的思想做最小生成树,但是处理的时候,把所有边权相同的边记录下来,分进一组。

之后试着从每组里dfs选边,使整张图连通,在这个过程中就可以统计出方案数

读入的边出入点要离散化。注意数组范围。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstring>
 6 using namespace std;
 7 const int mxn=10000;
 8 int n,m;
 9 int sum;
10 int ans=1;
11 //
12 struct edge{//边
13     int x,y;
14     int v;
15 }e[mxn];
16 struct segment{
17     int st,ed;//区块起止点
18     int v;
19 }se[mxn];
20 int cnt;
21 int cmp(const edge a,const edge b){
22     return a.v<b.v;
23 }
24 //
25 int fa[mxn];
26 int find(int x){
27     if(fa[x]==x)return x;
28     return find(fa[x]);//不可压缩
29 }
30 //
31 void dfs(int x,int now,int t){//x 组编号   now现在处理的边编号  t使用的边编号
32     if(now==se[x].ed+1){
33         if(t==se[x].v)sum++;
34         return;
35     }
36     int u=find(e[now].x),v=find(e[now].y);
37     if(u!=v){
38         fa[u]=v;
39         dfs(x,now+1,t+1);//选用这条边
40         fa[u]=u;fa[v]=v;//还原状态
41     }
42     dfs(x,now+1,t);//不选这条边
43     return;
44 }
45
46 int main(){
47     scanf("%d%d",&n,&m);
48     int i,j;
49     for(i=1;i<=n;i++)fa[i]=i;//初始化并查集,处理边的连通
50     for(i=1;i<=m;i++)
51         scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].v);
52     sort(e+1,e+m+1,cmp);
53     int tot=0;//联通边数
54     for(i=1;i<=m;i++){
55         if(e[i].v!=e[i-1].v){//如果权值与之前不同
56             se[cnt].ed=i-1;se[++cnt].st=i;//分到新的一组
57         }
58         int u=find(e[i].x);
59         int v=find(e[i].y);
60         if(u!=v){fa[u]=v;se[cnt].v++;tot++;}
61     }
62     se[cnt].ed=m;
63     if(tot!=n-1){printf("0");return 0;}//未联通
64     for(i=1;i<=n;i++)fa[i]=i;//初始化并查集,处理边组的连通
65     for(i=1;i<=cnt;i++){
66         sum=0;
67         dfs(i,se[i].st,0);
68         ans=(ans*sum)%31011;
69         for(j=se[i].st;j<=se[i].ed;j++){
70             int u=find(e[j].x),v=find(e[j].y);
71             if(u!=v)fa[u]=v;
72         }
73     }
74     printf("%d",ans%31011);
75     return 0;
76 }
时间: 2024-11-03 22:44:53

Bzoj1016 最小生成树计数的相关文章

[JSOI2008][BZOJ1016] 最小生成树计数

1016: [JSOI2008]最小生成树计数 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 3379  Solved: 1336[Submit][Status][Discuss] Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的).由于不同的最小生成树可能很多,所以你只需要输出方案数对31011的

【bzoj1016】 JSOI2008—最小生成树计数

http://www.lydsy.com/JudgeOnline/problem.php?id=1016 (题目链接) 题意:求图的最小生成树计数. Solution  %了下题解,发现要写矩阵树,150++的程序什么鬼.于是就蒯了hzwer的简便方法.  将边按照权值大小排序,将权值相同的边分到一组,统计下每组分别用了多少条边.然后对于每一组进行dfs,判断是否能够用这一组中的其他边达到相同的效果.最后把每一组的方案数相乘就是答案.  注意并查集不要压缩路径,不然的话不好回溯. 代码: //

【JSOI2008】【BZOJ1016】最小生成树计数

我就爱写矩阵树定理!!! 就不写暴力!!! 1016: [JSOI2008]最小生成树计数 Time Limit: 1 Sec Memory Limit: 162 MB Submit: 3584 Solved: 1429 [Submit][Status][Discuss] Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的).由于不同的最小生成树可

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

1016: [JSOI2008]最小生成树计数 题目:传送门 题解: 神题神题%%% 据说最小生成树有两个神奇的定理: 1.权值相等的边在不同方案数中边数相等  就是说如果一种方案中权值为1的边有n条    那么在另一种方案中权值为1的边也一定有n条 2.如果边权为1的边连接的点是x1,x2,x3   那么另一种方案中边权为1的边连接的也一定是x1,x2,x3  如果知道了这两条定理那就很好做了啊: 因为等权边的条数一定,那么我们就可以预处理求出不同边权的边的条数 题目很人道的保证了边权相同的边

BZOJ_1016_[JSOI2008]_最小生成树计数_(dfs+乘法原理)

描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1016 给出一张图,其中具有相同权值的边的数目不超过10,求最小生成树的个数. 分析 生成树的计数有一个什么什么算法... 我真的企图研究了...但是智商捉急的我实在看不懂论文... 所以最后还是写了暴力... 当然暴力也要靠正确的姿势的. 首先来看一个结论: 同一张图的所有最小生成树中,边权值相同的边的数目是一定的. 也就是说,假如某一张图的某一棵最小生成树由边权值为1,1,2,2,2,3的

【BZOJ】【1016】【JSOI2008】最小生成树计数

Kruskal/并查集+枚举 唉我还是too naive,orz Hzwer 一开始我是想:最小生成树删掉一条边,再加上一条边仍是最小生成树,那么这两条边权值必须相等,但我也可以去掉两条权值为1和3的,再加上权值为2和2的,不也满足题意吗?事实上,如果这样的话……最小生成树应该是1和2,而不是1和3或2和2!!! 所以呢?所以对于一个图来说,最小生成树有几条边权为多少的边,都是固定的!所以我们可以做一遍Kruskal找出这些边权,以及每种边权出现的次数.然后,对于每种边权,比方说出现了$v_i$

JSOI2008 最小生成树计数

题解: 最小生成树的两个性质: 1.边权相等的边的个数一定. 2.做完边权为w的所有边时,图的连通性相同. 证明: 1.边权相等的边的个数不一样的话就不会都同时是最小生成树了. 2.假设每种方法的做完边权为w的连通性不同,那么假设i边和j边没有同时被选,那么我们完全可以在一种方案中加入i边(或j边),使得连通性增强,而后面费用更大的边用的更少,这样与这是最小生成树矛盾.于是,命题得证. 代码:不知为何,下面程序有bug,什么时候再回来A掉…… 1 type node1=record 2 x,y,

BZOJ 题目1016: [JSOI2008]最小生成树计数(Kruskal+Matrix_Tree)

1016: [JSOI2008]最小生成树计数 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 3569  Solved: 1425 [Submit][Status][Discuss] Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的).由于不同的最小生成树可能很多,所以你只需要输出方案数对3101

1016: [JSOI2008]最小生成树计数

1016: [JSOI2008]最小生成树计数 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 6200  Solved: 2518[Submit][Status][Discuss] Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的 最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的).由于不同的最小生 成树可能很多,所以你只需要输出方案数对3101