bzoj 1016 最小生成树计数

本文介绍了一种通过深度优先搜索(DFS)算法来计算给定加权图中不同最小生成树的数量的方法,并提供了完整的C++代码实现。文章首先确定构成最小生成树所需的边集,然后针对每种边权重进行DFS,计算满足条件的方案数。

题目大意:

现在给出了一个简单无向加权图 求这个图中有多少个不同的最小生成树

如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的

输出方案数对31011的模

思路:

首先我们求出这个最小生成树需要用的边,每种边权的边需要用多少个

然后因为注意到数据很小

可以直接dfs

对于每种权值的边dfs,求出该种权值的边满足最小生成树的方案有多少个

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstdlib>
 6 #include<cstring>
 7 #include<queue>
 8 #include<map>
 9 #include<vector>
10 #define ll long long
11 #define inf 2147483611
12 #define MAXN 110
13 #define MOD 31011
14 using namespace std;
15 inline int read()
16 {
17     int x=0,f=1;char ch=getchar();
18     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
19     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
20     return x*f;
21 }
22 struct data
23 {
24     int u,v,val;
25     bool operator < (const data &a) const
26     {
27         return val<a.val;
28     }
29 }e[MAXN*20];
30 struct edge {int l,r,num;}g[MAXN*20];
31 int n,m,cnt,f[MAXN],kd,ans,res;
32 void add(int u,int v,int w) {e[++cnt].u=u,e[cnt].v=v,e[cnt].val=w;}
33 int find(int x,bool k)
34 {
35     if(x==f[x]) return x;
36     if(k) return f[x]=find(f[x],1);
37     else return find(f[x],0);
38 }
39 bool ok(int u,int v,int k)
40 {
41     int fa=find(u,k),fb=find(v,k);
42     if(fa==fb) return 1;
43     else {f[fa]=fb;return 0;}
44 }
45 bool kruskal()
46 {
47     cnt=0;
48     for(int i=1;i<=m;i++)
49     {
50         if(e[i].val!=e[i-1].val) g[kd].r=i-1,g[++kd].l=i;
51         if(!ok(e[i].u,e[i].v,1)) cnt++,g[kd].num++;
52     }
53     g[kd].r=m;
54     if(cnt<n-1) return 0;
55     else return 1;
56 }
57 void dfs(int k,int pos,int v)
58 {
59     if(pos==g[k].r+1) {if(v==g[k].num) res++;return ;}
60     int t=find(e[pos].u,0);
61     if(!ok(e[pos].u,e[pos].v,0))
62     {
63         dfs(k,pos+1,v+1);
64         f[t]=t;
65     }
66     dfs(k,pos+1,v);
67 }
68 int main()
69 {
70     n=read(),m=read();
71     int a,b,c;
72     for(int i=1;i<=m;i++) {a=read(),b=read(),c=read();add(a,b,c);}
73     for(int i=1;i<=n;i++) f[i]=i;
74     sort(e+1,e+m+1);
75     if(!kruskal()) {printf("0");return 0;}
76     for(int i=1;i<=n;i++) f[i]=i;
77     ans=1;
78     for(int i=1;i<=kd;i++)
79     {
80         res=0;
81         dfs(i,g[i].l,0);
82         (ans*=res%MOD)%=MOD;
83         for(int j=g[i].l;j<=g[i].r;j++) ok(e[j].u,e[j].v,1);
84     }
85     printf("%d",ans);
86 }
View Code

 

转载于:https://www.cnblogs.com/yyc-jack-0920/p/7872980.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值