思路
刚看到的时候,因为 ((nleq 100)) ,所以想到了爆搜,但是这样做显然会 (TLE) ,所以我们手摸几组数据找找结论
然后能发现一个结论:一张图上的不同最小生成树中,权值相等的边的个数是不变的
小证明:用kruskal求最小生成树时,每一步都是最优的,如果有不同的最小生成树,则当前步的权值必然小于等于之前最小生成树当前步的选择。但是反证可得,如果有小于的话,此时的最小生成树就比之前的优了,和之前矛盾,所以权值相等的边的个数是不变的。
代码
#include<bits/stdc++.h>
using namespace std;
const int mod=31011;
struct node{
int from,to,w;
}e[1010];
struct kruskal{
int l,r,v;
}a[1010];//存i边的个数,l r是左右端点,v是i在最小生成树上的个数
int n,m,f[110],ans,q[110],num,sum;
int find(int x){return x==f[x]?x:find(f[x]);}
//不能路径压缩!!!
bool cmp(node a,node b){
return a.w<b.w;
}
void dfs(int x,int now,int k)//x是你当前找的值 now是第几个边 k是你选了的个数
{
if(now==a[x].r+1){
if(k==a[x].v) sum++;//保证和生成树所需的一样
return ;
}
int xx=find(e[now].from),yy=find(e[now].to);
if(xx!=yy)//看是否选这边就为环
{
f[xx]=yy;
dfs(x,now+1,k+1);//选
f[xx]=xx;f[yy]=yy;//复原
}
dfs(x,now+1,k);//不选
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<=m;i++)
scanf("%d%d%d",&e[i].from,&e[i].to,&e[i].w);
sort(e+1,e+m+1,cmp);
int tot=0;
for(int i=1;i<=m;i++){
if(e[i].w!=e[i-1].w) num++,a[num].l=i,a[num-1].r=i-1;
int xx=find(e[i].from),yy=find(e[i].to);
if(xx!=yy) f[xx]=yy,a[num].v++,tot++;
}//kruskal
if(tot!=n-1){
printf("0");
return 0;
}//如果构不成树,就可以输出0了
a[num].r=m;
ans=1;
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<=num;i++){
sum=0;
dfs(i,a[i].l,0);
ans=(ans*sum)%mod;
for(int j=a[i].l;j<=a[i].r;j++){
int xx=find(e[j].from),yy=find(e[j].to);
if(xx!=yy) f[xx]=yy;
}//弄完一个后,连起来保证不为环
}
printf("%d",ans);
return 0;
}