传送门
最小生成树计数
题意:求不同形态的最小生成树总数
I think
为什么会有不同形态的最小生成树?前提是有了权值相同的边。
我们可以证明,在不同的最小生成树中,权值相同的边的数量是相同的。首先,我们将每个点置于不同的集合中。取权值最小边集,去除环,合并剩余边的端点集合。无论去除环上的任意边,被该权值的边合并的端点集合数量不变,且形态一致。
同理对于权值次小边集,次次小边集……
于是问题转化为搜索每种权值的边集生成树的不同形态数,最后乘法原理解决。
需要注意的是,在使用并查集时不能路径压缩,因为搜索的回溯中不便更改。
Code
#include<cstdio>
#include<algorithm>
typedef long long LL;
const int sm = 1e2+5;
const int sn = 1e3+5;
const int Mod = 31011;
int N,M,tot,Ct;
int Fa[sm];
LL Ans=1,ret;
struct Ed {
int u,v,w;
bool operator < (const Ed&a ) const {
return w<a.w;
}
}e[sn];
struct Data { int l,r,v; }a[sn];
void read(int &x) {
char ch=getchar();x=0;
while(ch>'9'||ch<'0') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
}
int Find(int x) { return x==Fa[x]?x:Find(Fa[x]); }
void Dfs(int x,int cur,int k) {
if(cur==a[x].r+1) {
if(k==a[x].v) ++ret;
return;
}
int p=Find(e[cur].u);
int q=Find(e[cur].v);
if(p!=q) {
Fa[p]=q;
Dfs(x,cur+1,k+1);
Fa[p]=p,Fa[q]=q;
}
Dfs(x,cur+1,k);
}
int main() {
int u,v;
read(N),read(M);
for(int i=1;i<=M;++i)
read(e[i].u),read(e[i].v),read(e[i].w);
std::sort(e+1,e+M+1);
for(int i=1;i<=N;++i) Fa[i]=i;
for(int i=1;i<=M;++i) {
if(e[i].w!=e[i-1].w) a[Ct].r=i-1,a[++Ct].l=i;
u=Find(e[i].u),v=Find(e[i].v);
if(u!=v) Fa[u]=v,++a[Ct].v,++tot;
}
a[Ct].r=M;
if(tot!=N-1) { puts("0");return 0; }
for(int i=1;i<=N;++i) Fa[i]=i;
for(int i=1;i<=Ct;++i) {
if(a[i].v&&a[i].r-a[i].l+1!=a[i].v) {
ret=0,Dfs(i,a[i].l,0);
Ans=Ans*ret%Mod;
}
for(int j=a[i].l;j<=a[i].r;++j) {
u=Find(e[j].u),v=Find(e[j].v);
if(u!=v) Fa[u]=v;
}
}
printf("%lld\n",Ans);
return 0;
}