图论--连通图计数模板

问题:含有n个不同的点的连通图有多少种,即同构的图算是多个。

记 含有n个点的连通图个数为 F[n] ;

  含有n个点的不连通图个数为 G[n] ;

  含有n个点的图的个数为 H[n] = 2^(n*(n-1)/2) ;

  有  F[n] + G[n] = H[n] ;  F[n] = H[n] - G[n] ;

因此要求 F[n] 只需求 G[n] ;

求 G[n] :枚举 1 号点所在的连通块大小为 k ( 1 ~ n-1 ) ;

     当 1 号点所在连通块大小为 k 时: k个点选取情况为组合数  C[n-1][k-1]

                     该连通块的种类数确定 k 个点后,连通块的种类数为 F[k] 

                     剩余 n-k 个点组成的图的种类数 H[n-k]

                     因此情况数为 C[n-1][k-1] * F[k] * H[n-k]

     G[n]为所有枚举的情况数总和  Σ( k : 1 ~ n-1 ) ( C[n-1][k-1] * F[k] * H[n-k] )

定初始值 F[1] = 1 , G[1] = 1

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 #include<math.h>
 5 using namespace std;
 6 typedef long long ll;
 7 
 8 const int maxn=1e3+5;
 9 const int mod=1e9+7;
10 
11 ll C[maxn][maxn];        //组合数
12 ll F[maxn],G[maxn],H[maxn];
13 
14 ll QP(ll a,ll n){        //快速幂
15     ll tmp=a,ans=1;
16     while(n){
17         if(n&1)ans=ans*tmp%mod;
18         tmp=tmp*tmp%mod;
19         n>>=1;
20     }
21     return ans;
22 }
23 
24 void init(){
25     for(int i=1;i<maxn;++i)H[i]=QP(2,i*(ll)(i-1)/2);
26     for(int i=0;i<maxn;++i){
27         for(int j=0;j<=i;++j){
28             C[i][j]=(i&&j)?(C[i-1][j]+C[i-1][j-1])%mod:1;
29         }
30     }
31     F[1]=1;G[1]=1;
32     for(int i=2;i<maxn;++i){
33         G[i]=0;
34         for(int k=1;k<i;++k){
35             G[i]=(G[i]+C[i-1][k-1]*F[k]%mod*H[i-k]%mod)%mod;
36         }
37         F[i]=((H[i]-G[i])%mod+mod)%mod;
38     }
39 }
原文地址:https://www.cnblogs.com/cenariusxz/p/5688338.html