【解题思路】

  Kruskal的拓展。

  可以先对边排序,进行一次Kruskal,判断是否可行,并计算出每种权值的边需要多少条。

  然后暴力统计每种权值可行的方案数,根据乘法原理乘起来即可。复杂度o(210mlog2(m+α(n)))。

【参考代码】

 1 #pragma GCC optimize(2)
 2 #include <algorithm>
 3 #define REP(i,low,high) for(register int i=(low);i<=(high);++i)
 4 using namespace std;
 5  
 6 //quick_io {
 7 #include <cctype>
 8 #include <cstdio>
 9 inline long long getint()
10 {
11     char ch=getchar(); for(;!isdigit(ch)&&ch!='+'&&ch!='-';ch=getchar());
12     short sig=1; for(;ch=='+'||ch=='-';ch=getchar()) if(ch=='-') sig*=-1;
13     long long ret=0; for(;isdigit(ch);ch=getchar()) ret=(ret<<3)+(ret<<1)+ch-'0';
14     return sig*ret;
15 }
16 //} quick_io
17  
18 //find_union_set {
19 #include <cstring>
20 class find_union_set
21 {
22 private:int fat[110],stk[110];
23     int find(const int&element)
24     {
25         int ancestor=element,top=0;
26         for(;ancestor!=fat[ancestor];ancestor=fat[ancestor]) stk[top++]=ancestor;
27         for(;top--;fat[stk[top]]=ancestor); return ancestor;
28     }
29 public:
30     find_union_set() {REP(i,1,100) fat[i]=i;} void clear() {REP(i,1,100) fat[i]=i;}
31     find_union_set&operator=(const find_union_set&thr)
32     {
33         return memcpy(fat,thr.fat,sizeof thr.fat),*this;
34     }
35     bool same(const int&one,const int&thr) {return find(one)==find(thr);}
36     bool unite(const int&one,const int&thr)
37     {
38         return same(one,thr)?0:(fat[fat[one]]=fat[thr],1);
39     }
40 };
41 //} find_union_set
42  
43 struct edge
44 {
45     int fr,to,vl;
46     void input() {fr=getint(),to=getint(),vl=getint();}
47     bool operator<(const edge&thr)const{return vl<thr.vl;}
48 }edg[1010];
49  
50 static const int AwD=31011; int cnt[1010]={0}; find_union_set now,tmp,can;
51 int main()
52 {
53     int n=getint(),m=getint(); REP(i,1,m) edg[i].input(); sort(edg+1,edg+m+1);
54     int tot=0,ans=1; REP(i,1,m)
55     {
56         tot+=edg[i].vl!=edg[i-1].vl;
57         if(!now.same(edg[i].fr,edg[i].to)) now.unite(edg[i].fr,edg[i].to),++cnt[tot];
58     }
59     REP(i,2,n) if(!now.same(1,i)) return puts("0"),0; now.clear();
60     for(register int i=1,j=1,tot=1;i<=m;i=++j,++tot,now=can)
61     {
62         for(;j<=m&&edg[j].vl==edg[i].vl;++j); --j; int count=0;
63         for(register int status=1<<j-i+1;status--;)
64         if(__builtin_popcount(status)==cnt[tot])
65         {
66             tmp=now; bool flag=0; REP(k,i,j) if(status&(1<<k-i))
67             {
68                 if(flag=!tmp.unite(edg[k].fr,edg[k].to)) break;
69             }
70             if(!flag) {can=tmp; if(++count==AwD) count=0;}
71         }
72         (ans*=count)%=AwD;
73     }
74     return printf("%d\n",ans),0;
75 }
View Code