zoukankan      html  css  js  c++  java
  • 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
    ",ans); 
    117 }
  • 相关阅读:
    引用 AspNetCoreRateLimit => StatusCode cannot be set because the response has already started.
    Sublime Json 格式化
    gitlab 建立本地仓库
    R语言 启动报错 *** glibc detected *** /usr/lib64/R/bin/exec/R: free(): invalid next size (fast): 0x000000000263a420 *** 错误 解决方案
    范数
    SparkR-Install
    R语言扩展包dplyr——数据清洗和整理
    R语言与机器学习学习笔记
    sparkR原理
    data.frame类型数据如何将第一列值替换为行号
  • 原文地址:https://www.cnblogs.com/qzqzgfy/p/5582708.html
Copyright © 2011-2022 走看看