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

262 篇文章 0 订阅
49 篇文章 0 订阅

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()]);
	}
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值