1543: 生成树计数
首先我们知道最小生成树的两个性质。
1.相同边权的出现次数相同。
2.相同边权的连通性相同。
所以我们可以直接DFS枚举相同的边权用了哪些,然后并查集撤销就可以了。
快的飞起。
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=50005,MAXM=100005,MOD=1000003;
int n,m,Ans=1,tot,Sum,V,fa[MAXN],P[MAXM],hsh[MAXM];
bool vis[MAXM];
struct xcw{
int x,y,w;
bool operator <(const xcw b)const{return w<b.w;}
}a[MAXM];
int get(int x){return x==fa[x]?x:fa[x]=get(fa[x]);}
void Kruskal(){
tot=0;
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=m;i++){
int fx=get(a[i].x),fy=get(a[i].y);
if(fx==fy) continue;
fa[fy]=fx;V+=a[i].w;tot++;hsh[P[i]]++;
}
}
void Work(){
tot=0;int Now=0;
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=m;i++)
if(vis[i]){
int fx=get(a[i].x),fy=get(a[i].y);
if(fx==fy) continue;
fa[fy]=fx;Now+=a[i].w;tot++;
}
if(tot==n-1&&Now==V) Sum++;
}
void DFS(int Num,int Now,int R){
if(Now>R){if(Num==0) Work();return;}
vis[Now]=0,DFS(Num,Now+1,R);
vis[Now]=1,DFS(Num-1,Now+1,R);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
sort(a+1,a+1+m);
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=m;i++){P[i]=i;if(a[i].w==a[i-1].w) P[i]=P[i-1];}
Kruskal();
if(tot!=n-1){printf("0\n");return 0;}
for(int i=1;i<=m;i++) vis[i]=1;
for(int i=1,j;i<=m;i=j){
j=i+1;
while(P[i]==P[j]&&j<=m) j++;
Sum=0;DFS(hsh[P[i]],i,j-1);if(Sum) Ans=(Ans*Sum)%MOD;
}
printf("%d\n",Ans);
return 0;
}