2013-06-09 21:18:18Morris

[UVA][math][JAVA] 10643 - Facing Problem With Trees

 

Facing Problem With Trees
Input: standard input
Output: standard output
Time Limit: 3 seconds


In this problem you are to find the number ( Let P ) of ordered trees where each of the tree consists of exactly m edges and each of the nodes has out-degree either exactly two or zero and the root has even out-degree. For example, if there are four edges, we get the following three trees.

 

Input

 

The first line in the input file is an integer representing the number of test cases. Each of the test cases follows below. Each case consists an integer representing various even values of m ( 2 ≤ m ≤ 500 ).


Output

 

For each test case, first print the serial number of the case and then print the value of P  separated by an space from the serial number. You should use Big Integer operation to print P and P has maximum 200 digits.

 

Sample Input

3

4

10

14

Sample Output

Case 1: 3
Case 2: 126
Case 3: 1716

 


Problem setter: Anupam Bhattacharjee, CSE, BUET

Thanks to Adrian Kuegel for his alternate solution.

"~~ NP ≠ P as NP means never possible and P means possible. Where is my Turing award of 2999?? ~~"







思路很簡單,把卡塔蘭數(Catalan number)抓來使用。
然後 dp[i][j] 表示節點個數 i 個, 根節點具有 j 個分支。

因此 j 一定為偶數,對於卡塔蘭數 F[i] 代表有 2*i+1 個節點(補滿 dummy node)。

那麼可以得到 dp[i][j-2] += dp[i-f1-f2]*F[ff1]*[ff2]

f1 是新增的第一分支的節點個數, F[ff1] 是這個樹的方法數(即卡塔蘭數)
同理 f2, ff2。


import java.util.*;
import java.math.BigInteger;

public class Main {
    static BigInteger[] F = new BigInteger[255];
    static BigInteger[] F2 = new BigInteger[505];
    static BigInteger[][] dp = new BigInteger[505][505];

    public static void main(String[] args) {
        F[0] = BigInteger.ONE;
        for (int i = 1; i < 255; i++) {
            F[i] = F[i - 1].multiply(BigInteger.valueOf(4 * i - 2)).divide(
                    BigInteger.valueOf(i + 1));
        }
        for (int i = 0; i < 505; i++)
            F2[i] = BigInteger.ZERO;
        for (int i = 0; i < 255; i++) {
            for (int j = 0; j < 255; j++) {
                if (i * 2 + 1 + j * 2 + 1 >= 505)
                    break;
                F2[i * 2 + 1 + j * 2 + 1] = F2[i * 2 + 1 + j * 2 + 1].add(F[i]
                        .multiply(F[j]));
            }
        }
        for (int i = 0; i < 505; i++)
            for (int j = 0; j < 505; j++)
                dp[i][j] = BigInteger.ZERO;
        dp[0][0] = BigInteger.valueOf(1);
        dp[1][0] = BigInteger.valueOf(1);
        dp[3][2] = BigInteger.valueOf(1);
        for (int i = 5; i < 505; i += 2) {
            dp[i][2] = F[(i - 1) / 2];
            for (int j = 4; j < i; j += 2) {
                for (int k = 2; k <= i; k += 2) {
                    dp[i][j] = dp[i][j].add(dp[i - k][j - 2].multiply(F2[k]));

                }
            }
        }
        Scanner cin = new Scanner(System.in);
        int testcase = cin.nextInt(), cases = 0;
        while (testcase-- != 0) {
            int n = cin.nextInt();
            BigInteger ret = BigInteger.ZERO;
            for (int i = 2; i <= n; i++)
                ret = ret.add(dp[n + 1][i]);
            System.out.printf("Case %d: %s\n", ++cases, ret);
        }
    }
}