Problem Description
Give you two definitions tree and rooted tree. An undirected connected graph without cycles is called a tree. A tree is called rooted if it has a distinguished vertex r called the root. Your task is to make a program to calculate
the number of rooted trees with n vertices denoted as Tn. The case n=5 is shown in Fig. 1.


Input
There are multiple cases in this problem and ended by the EOF. In each case, there is only one integer means n(1<=n<=40) .
Output
For each test case, there is only one integer means Tn.
Sample Input
1 2 5
Sample Output
1 1 9
题意:给出n个结点,问构成一个有根树,有多少种表示形式
思路:用f(n)表示所要求的解,n个结点时,除去一个根结点。先从整数拆分上考虑,实际上是n-1个结点的整数拆分形式,在拆分后,当中会有重复的情况,这又涉及到重复组合的问题。
例如n=5时,4=1+1+1+1=1+1+2=1+3=2+2=4,用加法原理有f(5) = C(f(1)+4-1,4) + C(f(1) + 2 - 1, 2) * C(f(2) + 1 - 1, 1) + C(f(1) + 1 - 1, 1) * C(f(3) + 1 - 1, 1) + C(f(2) + 2 - 1, 2) + C(f(4) + 1 - 1, 1)
注意,输出结果要有long表示,刚开始用int提交出错
代码如下
import java.io.FileReader;
import java.io.OutputStreamWriter;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.PrintWriter;
import java.util.Scanner;
public class Main implements Runnable
{
private static final boolean DEBUG = false;
private Scanner cin;
private PrintWriter cout;
private static final int N = 41;
private static final int[] step = new int[N];
private static final long[] dp = new long[N];
private int n;
private void init()
{
try {
if (DEBUG) {
cin = new Scanner(new BufferedReader(new FileReader("f:\\OJ\\uva_in.txt")));
} else {
cin = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
}
cout = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
dp[1] = dp[2] = 1;
for (int i = 3; i < N; i++) {
dp[i] = 0;
dfs(0, 1, i - 1, 0);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private boolean input()
{
if (!cin.hasNextInt()) return false;
n = cin.nextInt();
return true;
}
private long c(long n, long m)
{
m = Math.min(m, n - m);
long ans = 1;
for (int i = 0; i < m; i++) {
ans = ans * (n - i) / (i + 1);
}
return ans;
}
private void dfs(int dep, int start, int num, int sum)
{
if (sum > num) return;
if (sum == num) {
long s = 1;
long k = 1;
for (int i = 1; i < dep; i++) {
if (step[i] != step[i - 1]) {
s *= c(dp[step[i - 1]] + k - 1, k);
k = 0;
}
k++;
}
s *= c(dp[step[dep - 1]] + k - 1, k);
dp[num + 1] += s;
return;
}
for (int i = start; i <= num; i++) {
step[dep] = i;
dfs(dep + 1, i, num, sum + i);
}
}
private void solve()
{
cout.println(dp[n]);
cout.flush();
}
@Override
public void run()
{
init();
while (input())
{
solve();
}
}
public static void main(String[] args)
{
// TODO code application logic here
new Thread(new Main()).start();
}
}