Topic links
The minimum spanning tree has two properties:
1. The number of occurrences of a certain weight value in different MST is certain.
2. In different MST, the state of the connected blocks formed is the same after the edges of a certain weight are connected.
\ (solution1\)
By these two properties, you can first ask for an MST, and then enumerate each set of edges (the same weight as a set of edges) for each set of sides of Dfs (\ (O (2^{10}) \), if some scheme connectivity is the same as MST (record the number of connected blocks). The sum++.
Finally, based on the multiplication principle, the final answer is to multiply all sums.
\ (solution2\)
It is easy to think of Matrixtree theorem.
Press Benquan from small to large to handle each group of edges, before joining this group of edges, the previous edge will constitute some connected blocks, and this group of edges will certainly connect some connected blocks, such as (I do not know where this figure is):
Consider each connected block that was formed as a point, and this becomes a spanning tree count, which is the number of schemes that are the edges of that weight. Such as:
Based on the multiplication principle, we just have to figure out the scheme for each group of edges, and then multiply them.
//920kb 68ms#include <cstdio>#include <cctype>#include <vector>#include <cstring>#include <algorithm>#define GC () GetChar ()#define MOD (31011)Const intn=102, m=1002;intN,m,a[n][n],tmp[n][n],fa[n],bel[n],ans;BOOLvis[n];std::vector<int> V[n];structedge{intFr,to,val;BOOL operator< (ConstEdge &a)Const{returnval<a.val; }}E[M];inline intRead () {intnow=0;Register CharC=GC (); for(;! IsDigit (c); C=GC ()); for(; IsDigit (c); now=now*Ten+c-' 0 ', C=GC ());returnNow;}intGET_FA (intXint*F) {///Two and check sets, one maintains connectivity in MST, one maintains the connected block. returnX==F[X]?X:F[X]=GET_FA (f[x],f);}voidGauss (intN) { for(intI=1; i<n; ++i) for(intj=1; j<n; ++J) (a[i][j]+=mod)%=mod;//! BOOLf=0; for(intj=1; j<n; ++J) { for(intI=j+1; i<n; ++i) while(A[i][j]) {intT=A[J][J]/A[I][J]; for(intK=j; k<n; ++k) a[j][k]= (a[j][k]-t*a[i][k]%mod+mod)%mod; for(intK=j; k<n; ++k) Std::swap (A[i][k],a[j][k]); f^=1; }if(! A[j][j]) {ans=0; Break;} Ans=ans*a[j][j]%mod; }if(f) Ans=mod-ans;//!}voidCalc () { for(intI=1; i<=n; ++i)if(Vis[i]) V[get_fa (I,bel)].push_back (i), vis[i]=0;//processes the points contained in each connected block (the representative element of the original connected block). for(intx=1; x<=n; ++X)if(V[x].size () >1) {memset (A,0,sizeofA); for(intI=0, Lim=v[x].size (); i<lim; ++i) for(intA=v[x][i],b,j=i+1; j<lim; ++J) {b=v[x][j];if(Tmp[a][b]) {//tmp[][] as the edge matrix can not be emptied, because the two connected blocks no longer appear at the same time. A[I][J]=A[J][I]=-TMP[A][B]; A[I][I]+=TMP[A][B], a[j][j]+=tmp[a][b]; }} Gauss (V[x].size ()); } for(intI=1; i<=n; ++i) V[i].clear (), Bel[i]=fa[i]=get_fa (I,bel);//Calculate the end of a certain kind of edge to the same connected block up. }intMain () {N=read (), M=read (); for(intI=1; i<=m; ++i) E[i].fr=read (), E[i].to=read (), E[i].val=read (); Std::sort (E+1E+1+M); for(intI=1; i<=n; ++i) fa[i]=bel[i]=i; e[0].val=e[1].val, ans=1; for(intR1,r2,i=1; i<=m; ++i) {if(E[i].val!=e[i-1].val) Calc (); R1=get_fa (E[I].FR,FA), R2=get_fa (E[I].TO,FA);if(R1==R2)Continue;//fa[r1]=r2;//not connected for the time being. vis[r1]=vis[r2]=1; ++TMP[R1][R2], ++TMP[R2][R1];//, ++TMP[R1][R1], ++tmp[r2][r2];//point of the degree matrix can be later based on the edge processing, tmp[][] used to do the edge matrix. Best of all, you can not empty it. BEL[GET_FA (E[i].fr,bel)]=get_fa (E[i].to,bel);//Statistics out each connected block. } Calc ();//the last Edge for(intI=1; i<n; ++i)if(Bel[i]!=bel[i+1]) {ans=0; Break;} printf"%d", Ans);return 0;}
bzoj.1016. [JSOI2008] Minimum spanning tree count (Matrix tree theorem Kruskal)