题意:给定n,问有n个点的连通图有多少种,每个点是不同的。
分析:求出有n个点的图有多少种,求出不连通的有多少种,相减即可。求有n个点的不连通图时,枚举第n个点所在的连通分支有几个点,有k个点的话,除去第n点,还要选k-1个点,有C(n - 1, k -1)种选法。剩余n-k个点,这n-k个点随意构图,每两点间要么有边,要么没边,两种选择。有2^C(n-k,2)种情况。则用C(n - 1, k -1)乘以2^C(n-k,2)再乘以k个点构成连通图的情况总数,这样规模为n的问题转化为规模为k的子问题。dp处理即可。
import java.io.*;
import java.util.*;
import java.math.*;
public class Main {
static public BigInteger cal(int n, int k) {
BigInteger ret = new BigInteger("1");
for (int i = n; i > n - k; i--)
ret = ret.multiply(BigInteger.valueOf(i));
for (int i = 1; i <= k; i++)
ret = ret.divide(BigInteger.valueOf(i));
return ret;
}
static public void main(String[] args) {
BigInteger a[] = new BigInteger[51];
a[1] = new BigInteger("1");
for (int i = 2; i <= 50; i++) {
a[i] = new BigInteger("0");
for (int j = 1; j < i; j++) {
a[i] = a[i].add(a[j].multiply(cal(i - 1, j - 1).multiply(
new BigInteger("2").pow((i - j) * (i - j - 1) / 2))));
}
a[i] = new BigInteger("2").pow(i * (i - 1) / 2).subtract(a[i]);
}
Scanner cin = new Scanner(new BufferedInputStream(System.in));
while (cin.hasNext())
{
int x = cin.nextInt();
if (x == 0)
return;
System.out.println(a[x]);
}
}
}