当前位置:编程学习 > C/C++ >>

UVa 10247 Complete Tree Labeling (组合数学&高精度)

10247 - Complete Tree Labeling
Time limit: 15.000 seconds
 
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=1188
 
A complete k-ary tree is a k-ary tree in which all leaves have same depth and all internal nodes have degree k. This k is also known as the branching factor of a tree. It is very easy to determine the number of nodes of such a tree. Given the depth and branching factor of such a tree, you will have to determine in how many different ways you can number the nodes of the tree so that the label of each node is less that that of its descendants. You should assume that for numbering a tree with N nodes you have the (1, 2, 3, N-1, N) labels available.
 
 
 
Input
 
The input file will contain several lines of input. Each line will contain two integers k and d. Here k is the branching factor of the complete k-arytree and d is the depth of the complete k-ary tree (k>0, d>0, k*d<=21).
 
 
 
Output
 
For each line of input, produce one line of output containing a round number, which is the number of ways the k-ary tree can be labeled, maintaining the constraints described above.
 
 
 
Sample Input:
 
2 2
 
10 1
 
 
 
Sample Output:
 
80
 
3628800
 
 
思路:
 
用ans[i][j]表示深度为j的满i叉树的标号方案数,用node[i][j]表示深度为j的满i叉树的结点数。首先根结点必定是标最小的号码,然后还剩下node[i][j]-1个号码可用,我们要将他们分配给i棵子树,每棵子树得到m=node[i][j-1]个号码。用c[n][k]表示组合数,所以共有c[n[i][j]-1][m]*c[n[i][j]-1-m][m]*c[n[i][j]-1-2*m][m]*…*c[m][m]种分配方案。继续对子树标号,共有ans[i][j-1]^i种情况。故得到递归式:
 
ans[i][j]=c[n[i][j]-1][m]*c[n[i][j]-1-m][m]*c[n[i][j]-1-2*m][m]*…*c[m][m]*(ans[i][j-1]^i)。
 
 
高精度注意:当k=5,d=4时,结果有1774位。
 
 
 
完整代码:
 
/*0.549s*/  
  
import java.util.*;  
import java.io.*;  
import java.math.*;  
  
public class Main {  
    static Scanner cin = new Scanner(new BufferedInputStream(System.in));  
    static final int N = 22;  
  
    static int[][] node = new int[N][N];  
    static BigInteger[][] ans = new BigInteger[N][N];  
  
    static BigInteger c(int n, int k) {// 计算组合数  
        if (k > n)  
            return BigInteger.ZERO;  
        if (k > n - k)  
            return c(n, n - k);  
        BigInteger ans = BigInteger.ONE;  
        for (int i = 0; i < k; ++i)  
            ans = ans.multiply(BigInteger.valueOf(n - i)).divide(BigInteger.valueOf(i + 1));  
        return ans;  
    }  
  
    static void init() {  
        for (int i = 1; i < N; ++i) {  
            int pow = 1;  
            node[i][0] = 1;  
            for (int j = 1; j < N; ++j) {  
                pow *= i;  
                node[i][j] = node[i][j - 1] + pow;// 计算深度为j的满i叉树的结点数  
            }  
        }  
        for (int i = 1; i < N; ++i) {  
            ans[i][0] = BigInteger.ONE;  
            for (int j = 1; i * j < N; ++j) {  
                ans[i][j] = BigInteger.ONE;  
                int m = node[i][j - 1];  
                for (int k = 0; k < i; ++k)  
                    ans[i][j] = ans[i][j].multiply(ans[i][j - 1]).multiply(c(node[i][j] - 1 - k * m, m));// 计算结果  
            }  
        }  
    }  
  
    public static void main(String[] arg) {  
        init();  
        while (cin.hasNextInt())  
            System.out.println(ans[cin.nextInt()][cin.nextInt()]);  
    }  
}  

 

 
补充:软件开发 , C++ ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,