描述
现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的 最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生 成树可能很多,所以你只需要输出方案数对31011的模就可以了。
输入
第一行包含两个数,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条。
输出
输出不同的最小生成树有多少个。你只需要输出数量对31011的模就可以了。
样例输入
4 6
1 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 4 1
样例输出
8
Analysis
(黄学长的一句话题解就没有一次性理解透过)
首先我们来分析样例,发现喵喵喵那么多的1怎么选啊?
看一波数据范围,相同权值的边最多只有10条,敢情210可以爆搜出选取方案
然而有什么用呢?难不成要21000
不,当然不是
面对最小生成树,就得拿出我们的老把戏–Kruskal
我们发现一个性质(自然不是我发现的):
对于一个图的不同最小生成树,每种方案所包含的每种权值的边的数量一定一致。
换句话说,把每种方案包含的所有边的边权都写下来,写出来的序列一定都一样。
既然这样,我们先做一遍Kruskal,记录下每种权值的边用了多少条
然后暴力dfs(210)来找合法的选择方案
最后运用乘法原理
over ovo
Little tips
由于这道题dfs时需要回溯,也就是说要把每个点的父亲改为自己
我们在find函数里就不能进行路径压缩的处理(反正也慢不到哪里去)
Code
/*created by xly*/
#include<bits/stdc++.h>
#define in read()
#define re register
#define ll long long
using namespace std;
inline int read(){
char ch;int f=1,res=0;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
while(ch>='0'&&ch<='9'){
res=(res<<1)+(res<<3)+(ch^48);
ch=getchar();
}
return f==1?res:-res;
}
const int p=31011,M=1e3+10;
int n,m,cnt=0;
int fa[105],sum=0;
inline int getfa(int x){return x==fa[x]?x:getfa(fa[x]);}
struct edge{
int u,v,w;
inline bool operator < (const edge &b)const{
return w<b.w;
}
}e[M];
struct node{int l,r,t;}a[M];
void Dfs(int tp,int now,int k){
if(now==a[tp].r+1){
if(k==a[tp].t) sum++;
return ;
}
int u=getfa(e[now].u),v=getfa(e[now].v);
if(u!=v){
fa[u]=v;
Dfs(tp,now+1,k+1);
fa[u]=u;fa[v]=v;
}
Dfs(tp,now+1,k);
}
int main(){
n=in;m=in;
for(re int i=1;i<=n;++i) fa[i]=i;
for(re int i=1;i<=m;++i){e[i].u=in;e[i].v=in;e[i].w=in; }
sort(e+1,e+m+1);int tot=0;
for(re int i=1;i<=m;++i){
if(e[i].w!=e[i-1].w) {a[++cnt].l=i;a[cnt-1].r=i-1; }
int u=getfa(e[i].u),v=getfa(e[i].v);
if(u!=v){fa[u]=v;a[cnt].t++;tot++; }
}
a[cnt].r=m;
if(tot!=n-1) return printf("0"),0;
for(re int i=1;i<=n;++i) fa[i]=i;
int ans=1;
for(re int i=1;i<=cnt;++i){
sum=0;
Dfs(i,a[i].l,0);
ans=(ans*1ll*sum)%p;
for(re int j=a[i].l;j<=a[i].r;++j){
int u=getfa(e[j].u),v=getfa(e[j].v);
if(u!=v) fa[u]=v;
}
}
cout<<ans;
return 0;
}