BZOJ 1005 明明的烦恼(Prufer数列)

本文介绍了一种利用Prufer序列解决特定树结构计数问题的方法。通过给定部分节点的度数,计算满足条件的不同树的总数。采用组合数学原理,详细解析了计算过程,并提供了Java实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1005

题意:给出一棵树的某些节点的度数d,有些未给。问满足这个条件的树有多少种?

思路:Prufer序列

对于此题,设给定的度数的点有w个,令:$sum=\sum_{i=1}^{w}(d[i]-1)$

那么在最后的n-2个Prufer数列中这sum个是已经确定的,这sum个位置是给出的w个数的排列,排列数量为:$cnt=C_{n-2}^{sum}\frac{sum!}{\prod_{i=1}^{w}(d[i]-1)!}$

那么剩下的n-2-sum个位置上要放剩下的n-w个点,每个位置都有n-w种,所以最后的答案为:$cnt=C_{n-2}^{sum}\frac{sum!}{\prod_{i=1}^{w}(d[i]-1)!}(n-w)^{n-2-sum}$

import java.util.*;
import java.text.*;
import java.math.*;

public class Main{
 
    public static void PR(String s){
        System.out.println(s);
    }
    
    public static void PR(int x)
    {
        System.out.println(x);
    }
    
      public static void PR(BigInteger x)
    {
        System.out.println(x);
    }
    
    public static void PR(double s)
    {
        java.text.DecimalFormat d=new java.text.DecimalFormat("#.000000");
        System.out.println(d.format(s));
    }
    
    
    static BigInteger p[]=new BigInteger[1005];
    static BigInteger ans;
    static int d[]=new int[1005];
    static int n;
    
    public static void main(String[] args){
        
        Scanner S=new Scanner(System.in);
        n=S.nextInt();
        int i;
        p[0]=BigInteger.ONE;
        for(i=1;i<=n;i++) p[i]=p[i-1].multiply(BigInteger.valueOf(i));
        
        int sum=0,w=0,flag=1;
        for(i=1;i<=n;i++) 
        {
            d[i]=S.nextInt();
            if(d[i]!=-1) 
            {
                sum+=d[i]-1;
                w++;
            }
            if(d[i]==0||d[i]>n-1) flag=0;
        }
        if(n==1)
        {
            if(d[1]==0||d[1]==-1) PR(1);
            else PR(0);
        }
        else if(n==2)
        {
            if((d[1]==-1||d[1]==1)&&(d[2]==-1||d[2]==1)) PR(1);
            else PR(0);
        }
        else if(flag==0) PR(0);
        else
        {
            ans=p[n-2].divide(p[n-2-sum]);
            for(i=1;i<=n;i++) if(d[i]!=-1)
            {
                ans=ans.divide(p[d[i]-1]);
            }
            for(i=1;i<=n-2-sum;i++) ans=ans.multiply(BigInteger.valueOf(n-w));
            PR(ans);
        }
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值