面向数据编程。因为同边权最大十个,所以可以状压。
定理:最小生成树每种边权的边数量不变。
懒得证了。
所以状压,枚举用了哪几个,然后并查集查一下,可以就++,乘起来,输出。
记得保存之前边的father数组。
#include<bits/stdc++.h>
using namespace std;
#define in read()
#define int long long
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;ch=getchar();
}return cnt*f;
}
const int mod=31011;
int n,m;
struct node{
int u,v,w;
}edge[1003];
int fa[103],tm[103];
map<int,int> Count;
bool cm(node a,node b){
return a.w<b.w;
}int all=0;
int F[103];
int lowbit(int x){
return x&(-x);
}
int get(int x){
int sum=0;
while(x){
x-=lowbit(x);sum++;
}return sum;
}
bool sm(node a,node b){
return a.w<b.w;
}
int find(int x){
if(x==fa[x])return x;
return fa[x]=find(fa[x]);
}
signed main(){
n=in;m=in;
for(int i=1;i<=m;i++){
int u=in;int v=in;int w=in;
edge[i]={u,v,w};
}
sort(edge+1,edge+m+1,sm);
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=m;i++){
int u=edge[i].u,v=edge[i].v;
int x=find(u),y=find(v);
if(x!=y){
Count[edge[i].w]++;
fa[x]=y;all++;
if(all==n-1)break;
}
}
if(all<n-1){cout<<"0";return 0;}
int ans=1;for(int i=1;i<=n;i++)fa[i]=i;int j;
for(int i=1;i<=m;){
for(j=i;edge[j].w==edge[j+1].w;j++);
if(Count[edge[i].w]){
memcpy(F,fa,sizeof fa);
int now=0;
for(int s=1;s<(1<<(j-i+1));s++){
if(get(s)!=Count[edge[i].w])continue;
memcpy(fa,F,sizeof F);int flag=1;
for(int k=i;k<=j;k++){
if((s>>(k-i))&1){
int a=find(edge[k].u),b=find(edge[k].v);
if(a==b){
flag=0;break;
}fa[a]=b;
}
}
if(flag)now++;
}
ans=ans*now%mod;
memcpy(fa,F,sizeof F);
for(int k=i;k<=j;k++){
int a=find(edge[k].u),b=find(edge[k].v);
if(a!=b)fa[a]=b;
}
}
i=j+1;
}cout<<ans;
return 0;
}