uva10247 - Complete Tree Labeling

Problem B

Complete Tree Labeling!

Input: standard input

Output: standard output

Time Limit: 45 seconds

Memory Limit: 32 MB

 

A complete k-ary tree is a k-ary tree in which all leaves have same depth and all internal nodes have degreek. Thisk 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 withN 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 integersk andd. Here k is the branching factor of the completek-ary tree andd 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 thek-ary tree can be labeled, maintaining the constraints described above.

 

Sample Input:

2 2

10 1

 

Sample Output:

80

3628800


  给一个满k叉数从1到N编号,父亲要小于儿子的编号,问深度为d的满k叉数有多少种编号方法。

  这道题要有逆向思维,用cnt[i][j]表示深度为j的i叉数有多少个结点,dp[i][j]表示深度为j的i叉树可以编号的方法数。一个深度为j的i叉树是由一个根和i个深度为j-1的i叉树组成的,根是一定要编号为1的。那么根下的第1个深度为j-1的i叉树的编号方法数:从cnt[i][j]-1里选cnt[i-1][j]个编号,再乘以dp[i-1][j](因为选的这cnt[i-1][j]个编号互不相同,和编号1-cnt[i-1][j]能构成的深度为j-1的i叉树的排列数相同)。同理根下的第2个深度为j-1的i叉树的编号方法数:从刚挑完剩下的cnt[i][j]-1-cnt[i-1][j]中选cnt[i-1][j]个编号,再乘以dp[i-1][j]。

  设s=cnt[i][j]-1,m=cnt[i-1][j],因此dp[i][j]=C(s,m)*dp[i-1][j]*C(s-m,m)*dp[i-1][j]*C(s-2m,m)*dp[i-1][j].....*C(m,m)*dp[i-1][j]

  cnt[i][j]=cnt[i][j-1]*2+1

  初始化cnt[i][0]=1,dp[i][0]=1。

  cnt不用大数,dp要大数。。写个JAVA真恶心。。方法要用static。。

import java.util.*;
import java.math.*;
public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		BigInteger [][]dp=new BigInteger[25][25];
		int [][]cnt=new int[25][25];
		int i,j,k;
		for(i=1;i<=21;i++){
			cnt[i][0]=1;
			dp[i][0]=BigInteger.ONE;
		}
		for(i=1;i<=21;i++)
			for(j=1;j<=21;j++) cnt[i][j]=cnt[i][j-1]*i+1;
		for(i=1;i<=21;i++)
			for(j=1;j<=21/i;j++){
				dp[i][j]=BigInteger.ONE;
				int m=cnt[i][j-1],s=cnt[i][j]-1;
				for(k=s;k>=m;k=k-m){
					dp[i][j]=dp[i][j].multiply(C(k,m)).multiply(dp[i][j-1]);
				}
			}
		Scanner read=new Scanner(System.in);
		while(read.hasNext()){
			int K=read.nextInt();
			int D=read.nextInt();
			System.out.println(dp[K][D]);
		}
	}
	static BigInteger C(int a,int b){
		BigInteger ret=BigInteger.ONE;
		int i;
		for(i=a;i>a-b;i--) ret=ret.multiply(BigInteger.valueOf(i));
		for(i=b;i>0;i--) ret=ret.divide(BigInteger.valueOf(i));
		return ret;
	}
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值