[JSOI2008]最小生成树计数

本文介绍了一种计算不同最小生成树数量的方法。通过构建最小生成树,并针对每条边找出所有可能的选择方案,利用乘法原理累计答案。文章包含完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题解:

我们可以知道每个不同的最小生成树对于一个边权所使用的数量都是相同的.
那么我们就可以先做一次最小生成树,然后对于每一个最小生成树中的边权搜索出所有的可以选取的方案,然后乘法原理累计答案即可.

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<cstring>
 7 #include<queue>
 8 #include<vector>
 9 #define MAXN 500010
10 #define RG register
11 #define LL long long int
12 using namespace std;
13 const int INF=1e9;
14 const int mod=31011;
15 struct node{
16   int x,y,w;
17 }e[MAXN];
18 int n,m;
19 int fa[MAXN];
20 int L[MAXN],R[MAXN],T[MAXN],cnt;
21 int tot;
22 int ans=1,sum;
23 bool cmp(node a,node b){ return a.w<b.w;}
24 int find(int x)
25 {
26   if(fa[x]==x) return x;
27   else return find(fa[x]);
28 }
29 void dfs(int id,int now,int num)
30 {
31   if(now==R[id]+1)
32     {
33       if(num==T[id]) sum++;
34       return;
35     }
36   int f1=find(e[now].x),f2=find(e[now].y);
37   if(f1!=f2){
38     fa[f2]=f1;
39     dfs(id,now+1,num+1);
40     fa[f1]=f1;fa[f2]=f2;
41   }
42   dfs(id,now+1,num);
43 }
44 int main()
45 {
46   freopen("1.in","r",stdin);
47   scanf("%d%d",&n,&m);
48   for(int i=1;i<=m;i++) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
49   sort(e+1,e+m+1,cmp);for(int i=1;i<=n;i++) fa[i]=i;
50   for(int i=1;i<=m;i++)
51     {
52       if(e[i].w!=e[i-1].w) R[cnt]=i-1,L[++cnt]=i;
53       int f1=find(e[i].x),f2=find(e[i].y);
54       if(f1!=f2){ fa[f2]=f1;T[cnt]++;tot++;}
55     }
56   R[cnt]=m;
57   if(tot!=n-1){ printf("0\n");return 0;}
58   for(int i=1;i<=n;i++) fa[i]=i;
59   for(int i=1;i<=cnt;i++){
60     sum=0;
61     dfs(i,L[i],0);
62     (ans*=sum)%=mod;
63     for(int j=L[i];j<=R[i];j++){
64       int f1=find(e[j].x),f2=find(e[j].y);
65       if(f1!=f2){ fa[f2]=f1;}
66     }
67   }
68   printf("%d\n",ans);
69   return 0;
70 }

 

转载于:https://www.cnblogs.com/Landlord-greatly/p/8082802.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值