BZOJ 1016 最小生成树计数
http://www.lydsy.com/JudgeOnline/problem.php?id=1016
思路:
有这样一个性质:同一个图中最小生成树的权值相同的边数量相同。
我们来证明一下:假如一开始全部初始化,i的并查集父亲为i,那么假如最小权值的边没有构成环,那么这些边全部选入。
假如构成了环,那么必须会砍掉一些边,但不论怎么砍,这时构成的联通集合是一样的,而且砍掉的数量也一定一样。
那么怎么拓展到图中已经有一些边的情况呢?很简单,就是讲已经连起来的点缩成一个点,这样就和一开始的情况一样了,这样此时的边可能出现"自环",不过由于是最小生成树,这条边的权值一定大于等于环上的任意一条边,所以这条边不会被选入。
这样就简单了,我们用并查集维护,对相同权值的边的每个联通块,我们都做矩阵树定理,利用乘法原理,一个一个乘起来。
1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 #include<vector> 7 const int Mod=31011; 8 const double eps=1e-6; 9 std::vector<int>v[115]; 10 struct edge{ 11 int u,v,w; 12 }e[200005]; 13 int fa[115],Fa[115],n,m,vis[115]; 14 int c[115][115],g[115][115]; 15 int read(){ 16 char ch=getchar();int t=0,f=1; 17 while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} 18 while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} 19 return t*f; 20 } 21 bool cmp(edge a,edge b){ 22 return a.w<b.w; 23 } 24 int find(int x,int f[]){ 25 if (f[x]==x) return x; 26 else return find(f[x],f); 27 } 28 int sgn(double x){ 29 if (x<-eps) return -1; 30 if (x>eps) return 1; 31 return 0; 32 } 33 int gauss(int a[][115],int n){ 34 int res=1; 35 for (int i=1;i<=n;i++) 36 for (int j=1;j<=n;j++) 37 a[i][j]%=Mod; 38 for (int i=1;i<=n;i++){ 39 for (int j=i+1;j<=n;j++) 40 while (a[j][i]){ 41 int t=a[i][i]/a[j][i]; 42 for (int k=i;k<=n;k++) 43 a[i][k]=(a[i][k]-t*a[j][k])%Mod; 44 for (int k=i;k<=n;k++) 45 std::swap(a[i][k],a[j][k]); 46 res=-res; 47 } 48 if (a[i][i]==0) return 0; 49 res=(res*a[i][i])%Mod; 50 } 51 if (res<0) res=-res; 52 res=(res+Mod)%Mod; 53 return res; 54 } 55 int main(){ 56 n=read();m=read(); 57 memset(g,0,sizeof g); 58 for (int i=1;i<=n;i++) 59 v[i].clear(); 60 for (int i=1;i<=m;i++){ 61 e[i].u=read(),e[i].v=read(),e[i].w=read(); 62 } 63 int ans=1; 64 for (int i=1;i<=n;i++) fa[i]=i,vis[i]=0; 65 std::sort(e+1,e+1+m,cmp); 66 e[0].w=e[1].w; 67 int Edge=-1; 68 for (int i=1;i<=m+1;i++){ 69 if (i==m+1||e[i].w!=Edge){ 70 for (int j=1;j<=n;j++) 71 if (vis[j]) 72 v[find(j,Fa)].push_back(j),vis[j]=0; 73 for (int j=1;j<=n;j++) 74 if (v[j].size()>1){ 75 for (int k=1;k<=n;k++) 76 for (int l=1;l<=n;l++) 77 c[k][l]=0; 78 int len=v[j].size(); 79 for (int a=0;a<len;a++) 80 for (int b=a+1;b<len;b++){ 81 int a1=v[j][a],b1=v[j][b]; 82 c[a+1][b+1]=(c[b+1][a+1]-=g[a1][b1]); 83 c[a+1][a+1]+=g[a1][b1]; 84 c[b+1][b+1]+=g[a1][b1]; 85 } 86 int res=(int)gauss(c,len-1); 87 ans=(ans*res)%Mod; 88 for (int a=0;a<len;a++) 89 fa[v[j][a]]=j; 90 } 91 for (int j=1;j<=n;j++){ 92 v[j].clear(); 93 Fa[j]=fa[j]=find(j,fa); 94 } 95 if (i==m+1) break; 96 Edge=e[i].w; 97 } 98 int u=e[i].u,v=e[i].v; 99 int u1=find(u,fa),v1=find(v,fa); 100 if (u1==v1) continue; 101 vis[u1]=vis[v1]=1; 102 Fa[find(u1,Fa)]=find(v1,Fa); 103 g[u1][v1]++; 104 g[v1][u1]++; 105 } 106 int U=find(1,fa); 107 for (int i=2;i<=n;i++) 108 if (U!=find(i,fa)) { 109 puts("0"); 110 return 0; 111 } 112 if (m<n-1){ 113 puts("0"); 114 return 0; 115 } 116 printf("%d\n",ans); 117 }