第五题啦。开始针对语言咧,用 Java 来搞会非常简单~
题目链接
题目描述
An undirected graph is a set V of vertices and a set of E∈{V*V} edges.An undirected graph is connected if and only if for every pair (u,v) of vertices,u is reachable from v.
You are to write a program that tries to calculate the number of different connected undirected graph with n vertices.
For example,there are 4 different connected undirected graphs with 3 vertices.
题目输入
The input contains several test cases. Each test case contains an integer n, denoting the number of vertices. You may assume that 1<=n<=50.
The last test case is followed by one zero.
题目输出
For each test case output the answer on a single line.
样例输入
1 2 3 4 0
样例输出
1 1 4 38
解题思路
关键词:容斥原理,组合数,联通分量
计算过程中需要用到三个值:
- 由 个点组成的图一共有多少种。
- 由 个点组成且不联通的图一共有多少种。
- 由 个点组成且联通的图一共有多少种。
先来思考 如何计算。
包含 个节点的图,最多有 条边。因无需考虑联调性,所以每条边都可有可无。因此总共可组成 种不同的图,记为 。
再来考虑 如何计算。
如果图是不联通的,则必有两个或两个以上的联通分量。不妨设第 个节点所在的联通分量有 个节点。我们从 个节点中选取 个节点,来和第 个点组成联通分量,因此总共有 种联通分量。对于剩余的 个点的联通性无需关心,因此:
至于 利用容斥原理就很好求啦~
显然三者满足:
但是该题的答案巨大,超出64位整数的存储上限,因此对于大多数语言来说,选手需要手动实现大数的加减乘。
或者,偷懒用 Java 的 BigInteger 实验上述计算过程。
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
static BigInteger quickPower(BigInteger v, int p) {
if (p == 0) {
return BigInteger.ONE;
}
if (p == 1) {
return v;
}
BigInteger vv = quickPower(v, p / 2);
return vv.multiply(vv).multiply(quickPower(v, p & 1));
}
public static void main(String[] args) {
BigInteger[] c = new BigInteger[51];
BigInteger[] d = new BigInteger[51];
BigInteger[] t = new BigInteger[51];
BigInteger[][] combine = new BigInteger[51][51];
for (int i = 0; i <= 50; i++) {
for (int j = 0; j <= i; j++) {
if (j == 0 || i == j) {
combine[i][j] = BigInteger.ONE;
} else {
combine[i][j] = BigInteger.ZERO.add(combine[i-1][j-1]).add(combine[i-1][j]);
}
}
}
for (int i = 1; i <= 50; i++) {
t[i] = quickPower(BigInteger.valueOf(2), i*(i-1)/2);
d[i] = BigInteger.ZERO;
for (int j = 1; j < i; j++) {
d[i] = d[i].add(combine[i-1][j-1].multiply(c[j]).multiply(t[i-j]));
}
c[i] = t[i].subtract(d[i]);
}
Scanner reader=new Scanner(System.in);
while (reader.hasNextInt()) {
int n = reader.nextInt();
if (n != 0) {
System.out.println(c[n]);
}
}
return;
}
}