1492:最小生成树计数


【题目描述】

原题来自:JSOI 2008

现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。

【输入】

第一行包含两个数,n 和 m,表示该无向图的节点数和边数,每个节点用 1∼n 的整数编号;

接下来的 m 行,每行包含两个整数:a,b,c,表示节点 a,b 之间的边的权值为 c。

【输出】

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

【输入样例】

4 6
1 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 4 1

【输出样例】

8

【提示】

数据范围:

对于全部数据,1≤n≤100,1≤m≤1000,1≤c≤109

数据保证不会出现自回边和重边。

注意:具有相同权值的边不会超过 10 条。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int N = 1100,M = 1e3+7,mod = 31011;
int n,m,tot,cnt;
int ans,sum;
int l[N],r[N],va[N],pre[N];
struct E{
int from,to,w;
bool operator < (const E &b) const{
return w < b.w;
}
}e[M];
int find(int x){
return x==pre[x] ? x: find(pre[x]);
}
void read(){
scanf(“%d%d”,&n,&m);
for(int i=1;i<=m;i++)
scanf(“%d%d%d”,&e[i].from,&e[i].to,&e[i].w);
}
void dfs(int x,int now,int k){
if(now == r[x]+1){
if(k == va[x]) sum++;
return;
}
int fx = find(e[now].from),fy = find(e[now].to);
if(fx != fy){
pre[fx] = fy;
dfs(x,now+1,k+1);
pre[fx] = fx,pre[fy] = fy;
}
dfs(x,now+1,k);
}
void solve(){
sort(e+1,e+m+1);
for(int i=0;i<=110;i++) pre[i] = i;
for(int i=1;i <= m;i++){
if(e[i].w != e[i-1].w) cnt++,l[cnt]=i,r[cnt-1]=i-1;
int fx = find(e[i].from),fy = find(e[i].to);
if(fx != fy){
pre[fx] = fy;
va[cnt]++; tot++;
}
}
if(tot != n-1){
printf(“0”);return;
}
r[cnt] = m;
for(int i=0;i<=110;i++) pre[i] = i;
ans = 1;
for(int i=1;i <= cnt; i++){
sum = 0;
dfs(i,l[i],0);
ans = (ans*sum) % mod;
for(int j=l[i];j<=r[i];j++){
int fx = find(e[j].from),fy = find(e[j].to);
if(fx != fy) pre[fx] = fy;
}
}
printf(“%d”,ans);
}
int main(){
read();
solve();
return 0;
}

原创文章,作者:sunnyman218,如若转载,请注明出处:https://blog.ytso.com/275133.html

(0)
上一篇 2022年7月18日
下一篇 2022年7月18日

相关推荐

发表回复

登录后才能评论