问题:含有两边分别为 n 和 m 个不同的点的连通二分图有多少种,即同构的图算是多个。
记 含有 n , m 个点的连通图个数为 F[n][m] ;
含有 n , m 个点的不连通图个数为 G[n][m] ;
含有 n , m 个点的图的个数为 H[n][m] = 2^(n*m) ;
有 F[n][m] + G[n][m] = H[n][m] ; F[n][m] = H[n][m] - G[n][m] ;
因此要求 F[n][m] 只需求 G[n][m] ;
求 G[n][m] :枚举 1 号点所在的连通块大小为 k1 ( 1 ~ n ) + k2 ( 0 ~ m ) 且 k1、k2 不能同时取最大值;
当 1 号点所在连通块大小为 k1+k2 时: k1个点选取情况为组合数 C[n-1][k1-1]
k2个点选取情况为组合数 C[m][k2]
该连通块的种类数确定 k1+k2 个点后,连通块的种类数为 F[k1][k2]
剩余 n-k1 + m-k2 个点组成的图的种类数 H[n-k1][m-k2]
因此情况数为 C[n-1][k1-1] * C[m][k2] * F[k1][k2] * H[n-k1][m-k2]
G[n]为所有枚举的情况数总和
定初始值 F[0][0] = F[0][1] = F[1][0] = 1 , 其余有一维是 0 时 F 值为 0
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=55; 9 const int maxm=55; 10 const int mod=1e9+7; 11 12 ll C[maxn][maxn]; //组合数 13 ll F[maxn][maxm],G[maxn][maxm],H[maxn][maxm]; 14 15 ll QP(ll a,ll n){ //快速幂 16 ll tmp=a,ans=1; 17 while(n){ 18 if(n&1)ans=ans*tmp%mod; 19 tmp=tmp*tmp%mod; 20 n>>=1; 21 } 22 return ans; 23 } 24 25 void init(){ 26 for(int i=0;i<maxn;++i){ 27 for(int j=0;j<maxm;++j){ 28 H[i][j]=QP(2,i*j); 29 } 30 } 31 for(int i=0;i<maxn;++i){ 32 for(int j=0;j<=i;++j){ 33 C[i][j]=(i&&j)?(C[i-1][j]+C[i-1][j-1])%mod:1; 34 } 35 } 36 F[0][0]=F[1][0]=F[1][0]=1; 37 for(int i=2;i<maxn;++i)F[i][0]=0; 38 for(int i=2;i<maxm;++i)F[0][i]=0; 39 for(int i=1;i<maxn;++i){ 40 for(int j=1;j<maxm;++j){ 41 G[i][j]=0; 42 for(int k1=1;k1<=i;++k1){ 43 for(int k2=0;k2<=j;++k2){ 44 if(k1==i&&k2==j)continue; 45 G[i][j]+=C[i-1][k1-1]*C[j][k2]%mod*F[k1][k2]%mod*H[i-k1][j-k2]%mod; 46 G[i][j]%=mod; 47 } 48 } 49 F[i][j]=((H[i][j]-G[i][j])%mod+mod)%mod; 50 } 51 } 52 }