BZOJ 1005 [HNOI2008]明明的烦恼 ★(Prufer数列)

题意

N个点,有些点有度数限制,问这些点可以构成几棵不同的树。

思路


  【 Prufer数列】 Prufer数列是无根树的一种数列。在组合数学中,Prufer数列是由一个对于顶点标过号的树转化来的数列,点数为n的树转化来的Prufer数列长度为n-2。 一个Prufer数列唯一对应一棵树。 【 将树转化成Prufer数列的方法】 一种生成Prufer序列的方法是迭代删点,直到原图仅剩两个点。对于一棵顶点已经经过编号的树T,顶点的编号为{1,2,...,n},在第i步时,移去所有叶子节点(度为1的顶点)中标号最小的顶点和相连的边,并把与它相邻的点的编号加入Prufer序列中,重复以上步骤直到原图仅剩2个顶点。
  显然本题就是求不同的Prufer数列个数, 由于有些点有度数限制,假设这些点度数分别为d[i],则该点在数列中就需要出现d[i]-1次。 令sum = sigma(d[i]-1),则sum表示所有w个有度数限制的点在数列中占几位。 先为这些点分配位置:P1 = C(n-2, sum)*sum!/∏(d[i]-1)! 然后剩下n-w个点,n-sum-2个空位,P = P1 * (n-w) n-sum-2.

代码

  [cpp] /************************************************************** Problem: 1005 User: AbandonZHANG Language: Java Result: Accepted Time:1284 ms Memory:19092 kb ****************************************************************/ import java.util.*; import java.math.*; public class Main{ public static void main(String args[]){ Scanner cin = new Scanner(System.in); int a[] = new int[1005]; int n, w = 0, sum = 0; n = cin.nextInt(); BigInteger ww = BigInteger.ONE, ws; for (int i = 0; i < n; i ++){ a[i] = cin.nextInt(); if (a[i] > -1){ w ++; sum += (a[i] - 1); ww = ww.multiply(fac(a[i]-1)); } } ws = fac(sum); BigInteger res = BigInteger.ONE, wp = BigInteger.valueOf(n-w); res = res.multiply(C(n-2, sum)); res = res.multiply(ws.divide(ww)); res = res.multiply(wp.pow(n-sum-2)); System.out.println(res); cin.close(); } public static BigInteger fac(int n){ BigInteger res; res = BigInteger.ONE; while(n != 0){ res = res.multiply(BigInteger.valueOf(n)); n --; } return res; } public static BigInteger C(int n, int r){ BigInteger res = BigInteger.ONE; res = res.multiply(fac(n)); res = res.divide(fac(r).multiply(fac(n-r))); return res; } } [/cpp]

你可能感兴趣的:(2008)