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 6
1 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 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 }

 

posted @ 2016-07-12 22:41  SilverNebula  阅读(845)  评论(0编辑  收藏  举报
AmazingCounters.com