带标号的接通图计数
带标号的连通图计数
统计 n 个顶点的连通图有多少个,每个顶点有标号。记 f(n) 为带标记的连通图的个数,g(n) 为带标记的非连通图的个数,则 f(n) + g(n) = h(n) = 2^(n(n-1)/2) ;考虑 g(n) 的计数:按照结点 1 所在的联通分量的点数分类,设结点 1 所在联通分量包含 k 点(k = 1 ... n-1)则有 C(n-1, k -1) 种不同情况,每种情况下,结点 1 所在连通分量有 f(k) 种,剩余的 n - k 点组成的图有 h(n-k) 种,所以有递推关系:g(n) = ∑c(n-1, k-1)f(k)h(n-k), k = 1...n ;初始值为 f(1)=1, g(1)=1。
另外,h(n) / h(n-1) = 2^(n(n-1)/2-(n-1)(n-2)/2) = 2^(n-1),所以 h(n) = h(n-1)2^(n-1)
public class NumberOfConnectedGraph { public static long solve(int N) { long[] f = new long[N+1]; // 连通图数目 long[] g = new long[N+1]; // 非连通图数目 long[] h = new long[N+1]; // 图数目 f[1] = 1; g[1] = 1; h[1] = 1; for ( int n=2; n<=N; n++ ) { // h(n) = h(n-1) * 2^(n-1) h[n] = ( 1 << (n-1) ) * h[n-1]; long comb = 1; g[n] = 0; for ( int k=1; k<=n-1; k++ ) { // 递推 c(n-1,k-1) = c(n,k-2)*(n-k+1)/(k-1) comb = (k==1)?1:comb*(n-k+1)/(k-1); g[n] += comb * f[k] * h[n-k]; } f[n] = h[n] - g[n]; } return f[N]; } // 测试 public static void main(String[] args) { int[] v = { 3, 4, 5, 6 }; for ( int x : v ) { System.out.println(solve(x)); } } }