首页 > 代码库 > 最小生成树计数

最小生成树计数

Minimum Spanning Tree http://acm.hdu.edu.cn/showproblem.php?pid=4408

模板题

  1 #include<cstdio>  2 #include<cstring>  3 #include<vector>  4 #include<algorithm>  5 #define mt(a,b) memset(a,b,sizeof(a))  6 using namespace std;  7 typedef __int64 LL;  8 class MinST_count { ///最小生成树计数  9     typedef int typec;///边权的类型 10     static const int ME=1024;///边的个数 11     static const int MV=128;///点的个数 12     struct E { 13         int u,v; 14         typec w; 15         friend bool operator <(E a,E b) { 16             return a.w<b.w; 17         } 18     } e[ME]; 19     LL mod,ans,mat[MV][MV]; 20     int n,le,fa[MV],ka[MV],gk[MV][MV]; 21     bool vis[MV]; 22     vector<int> gra[MV]; 23     int getroot(int a,int b[]) { 24         return a==b[a]?a:b[a]=getroot(b[a],b); 25     } 26     LL det(LL a[][MV],int n) { ///生成树计数 27         for(int i=0; i<n; i++) 28             for(int j=0; j<n; j++) 29                 a[i][j]%=mod; 30         LL ret=1; 31         for(int i=1; i<n; i++) { 32             for(int j=i+1; j<n; j++) { 33                 while(a[j][i]) { 34                     LL t=a[i][i]/a[j][i]; 35                     for(int k=i; k<n; k++) 36                         a[i][k]=(a[i][k]-a[j][k]*t)%mod; 37                     for(int k=i; k<n; k++) 38                         swap(a[i][k],a[j][k]); 39                     ret=-ret; 40                 } 41             } 42             if(!a[i][i]) return 0; 43             ret=ret*a[i][i]%mod; 44         } 45         return (ret+mod)%mod; 46     } 47 public: 48     void init(int tn,int tmod) { ///传入点的个数,%tmod,点下标1开始 49         n=tn; 50         mod=tmod; 51         le=0; 52         mt(fa,0); 53         mt(ka,0); 54         mt(vis,0); 55         mt(gk,0); 56         mt(mat,0); 57     } 58     void add(int u,int v,typec w) { 59         e[le].u=u; 60         e[le].v=v; 61         e[le].w=w; 62         le++; 63     } 64     LL solve() {///返回生成树个数%mod 65         sort(e,e+le); 66         for(int i=1; i<=n; i++){ 67             fa[i]=i; 68             vis[i]=false; 69             gra[i].clear(); 70         } 71         typec pre=-1; 72         ans=1; 73         for(int h=0; h<=le; h++) { 74             if(e[h].w!=pre||h==le) { ///一组边加完 75                 for(int i=1; i<=n; i++) { 76                     if(vis[i]) { 77                         int u=getroot(i,ka); 78                         gra[u].push_back(i); 79                         vis[i]=false; 80                     } 81                 } 82                 for(int i=1; i<=n; i++) { ///枚举每个联通分量 83                     if(gra[i].size()>1) { 84                         mt(mat,0); 85                         int len=gra[i].size(); 86                         for(int a=0; a<len; a++) { ///构建矩阵 87                             for(int b=a+1; b<len; b++) { 88                                 LL la=gra[i][a],lb=gra[i][b]; 89                                 mat[a][b]=(mat[b][a]-=gk[la][lb]); 90                                 mat[a][a]+=gk[la][lb]; 91                                 mat[b][b]+=gk[la][lb]; 92                             } 93                         } 94                         LL ret=(LL)det(mat,len); 95                         ans=(ans*ret)%mod; 96                         for(int a=0; a<len; a++) 97                             fa[gra[i][a]]=i; 98                     } 99                 }100                 for(int i=1; i<=n; i++) {101                     ka[i]=fa[i]=getroot(i,fa);102                     gra[i].clear();103                 }104                 if(h==le)break;105                 pre=e[h].w;106             }107             int a=e[h].u;108             int b=e[h].v;109             int pa=getroot(a,fa);110             int pb=getroot(b,fa);111             if(pa==pb)continue;112             vis[pa]=vis[pb]=true;113             ka[getroot(pa,ka)]=getroot(pb,ka);114             gk[pa][pb]++;115             gk[pb][pa]++;116         }117         for(int i=2; i<=n&&ans; i++)118             if(ka[i]!=ka[i-1])119                 ans=0;120         ans=(ans+mod)%mod;121         return ans;122     }123 }gx;124 int main() {125     int n,m,p;126     while(~scanf("%d%d%d",&n,&m,&p),n|m|p) {127         gx.init(n,p);128         while(m--) {129             int u,v,w;130             scanf("%d%d%d",&u,&v,&w);131             gx.add(u,v,w);132         }133         printf("%I64d\n",gx.solve());134     }135     return 0;136 }
View Code

 

1016: [JSOI2008]最小生成树计数 http://www.lydsy.com/JudgeOnline/problem.php?id=1016

一样

  1 #include<cstdio>  2 #include<cstring>  3 #include<vector>  4 #include<algorithm>  5 #define mt(a,b) memset(a,b,sizeof(a))  6 using namespace std;  7 typedef long long LL;  8 class MinST_count { ///最小生成树计数  9     typedef int typec;///边权的类型 10     static const int ME=1024;///边的个数 11     static const int MV=128;///点的个数 12     struct E { 13         int u,v; 14         typec w; 15         friend bool operator <(E a,E b) { 16             return a.w<b.w; 17         } 18     } e[ME]; 19     LL mod,ans,mat[MV][MV]; 20     int n,le,fa[MV],ka[MV],gk[MV][MV]; 21     bool vis[MV]; 22     vector<int> gra[MV]; 23     int getroot(int a,int b[]) { 24         return a==b[a]?a:b[a]=getroot(b[a],b); 25     } 26     LL det(LL a[][MV],int n) { ///生成树计数 27         for(int i=0; i<n; i++) 28             for(int j=0; j<n; j++) 29                 a[i][j]%=mod; 30         LL ret=1; 31         for(int i=1; i<n; i++) { 32             for(int j=i+1; j<n; j++) { 33                 while(a[j][i]) { 34                     LL t=a[i][i]/a[j][i]; 35                     for(int k=i; k<n; k++) 36                         a[i][k]=(a[i][k]-a[j][k]*t)%mod; 37                     for(int k=i; k<n; k++) 38                         swap(a[i][k],a[j][k]); 39                     ret=-ret; 40                 } 41             } 42             if(!a[i][i]) return 0; 43             ret=ret*a[i][i]%mod; 44         } 45         return (ret+mod)%mod; 46     } 47 public: 48     void init(int tn,int tmod) { ///传入点的个数,%tmod,点下标1开始 49         n=tn; 50         mod=tmod; 51         le=0; 52         mt(fa,0); 53         mt(ka,0); 54         mt(vis,0); 55         mt(gk,0); 56         mt(mat,0); 57     } 58     void add(int u,int v,typec w) { 59         e[le].u=u; 60         e[le].v=v; 61         e[le].w=w; 62         le++; 63     } 64     LL solve() {///返回生成树个数%mod 65         sort(e,e+le); 66         for(int i=1; i<=n; i++){ 67             fa[i]=i; 68             vis[i]=false; 69             gra[i].clear(); 70         } 71         typec pre=-1; 72         ans=1; 73         for(int h=0; h<=le; h++) { 74             if(e[h].w!=pre||h==le) { ///一组边加完 75                 for(int i=1; i<=n; i++) { 76                     if(vis[i]) { 77                         int u=getroot(i,ka); 78                         gra[u].push_back(i); 79                         vis[i]=false; 80                     } 81                 } 82                 for(int i=1; i<=n; i++) { ///枚举每个联通分量 83                     if(gra[i].size()>1) { 84                         mt(mat,0); 85                         int len=gra[i].size(); 86                         for(int a=0; a<len; a++) { ///构建矩阵 87                             for(int b=a+1; b<len; b++) { 88                                 LL la=gra[i][a],lb=gra[i][b]; 89                                 mat[a][b]=(mat[b][a]-=gk[la][lb]); 90                                 mat[a][a]+=gk[la][lb]; 91                                 mat[b][b]+=gk[la][lb]; 92                             } 93                         } 94                         LL ret=(LL)det(mat,len); 95                         ans=(ans*ret)%mod; 96                         for(int a=0; a<len; a++) 97                             fa[gra[i][a]]=i; 98                     } 99                 }100                 for(int i=1; i<=n; i++) {101                     ka[i]=fa[i]=getroot(i,fa);102                     gra[i].clear();103                 }104                 if(h==le)break;105                 pre=e[h].w;106             }107             int a=e[h].u;108             int b=e[h].v;109             int pa=getroot(a,fa);110             int pb=getroot(b,fa);111             if(pa==pb)continue;112             vis[pa]=vis[pb]=true;113             ka[getroot(pa,ka)]=getroot(pb,ka);114             gk[pa][pb]++;115             gk[pb][pa]++;116         }117         for(int i=2; i<=n&&ans; i++)118             if(ka[i]!=ka[i-1])119                 ans=0;120         ans=(ans+mod)%mod;121         return ans;122     }123 }gx;124 int main() {125     int n,m,p;126     while(~scanf("%d%d",&n,&m)) {127         gx.init(n,31011);128         while(m--) {129             int u,v,w;130             scanf("%d%d%d",&u,&v,&w);131             gx.add(u,v,w);132         }133         printf("%lld\n",gx.solve());134     }135     return 0;136 }
View Code

 

 

end

最小生成树计数