BZOJ 1005 [HNOI2008] 明明的煩惱(組合數學 Purfer Sequence)

 

題目大意

 

自從明明學了樹的結構,就對奇怪的樹產生了興趣......php

給出標號爲 1 到 N 的點,以及某些點最終的度數,容許在任意兩點間連線,可產生多少棵度數知足要求的樹?java

 

Inputide

  第一行爲 N(0<N<=1000),接下來 N 行,第 i+1 行給出第 i 個節點的度數 Di,若是對度數不要求,則輸入 -1spa

Output3d

  一個整數,表示不一樣的知足要求的樹的個數,無解輸出 0code

 

作法分析

 

這題須要瞭解一種數列: Purfer Sequenceblog

咱們知道,一棵樹能夠用括號序列來表示,可是,一棵頂點標號(1~n)的樹,還能夠用一個叫作 Purfer Sequence 的數列表示ip

一個含有 n 個節點的 Purfer Sequence 有 n-2 個數,Purfer Sequence 中的每一個數是 1~n 中的一個數get

 

一個定理:一個 Purfer Sequence 和一棵樹一一對應event

 

先看看怎麼由一個樹獲得 Purfer Sequence

由一棵樹獲得它的 Purfer Sequence 總共須要 n-2 步,每一步都在當前的樹中尋找具備最小標號的葉子節點(度爲 1),將與其相連的點的標號設爲 Purfer Sequence 的第 i 個元素,並將此葉子節點從樹中刪除,直到最後獲得一個長度爲 n-2 的 Purfer Sequence 和一個只有兩個節點的樹

 

看看下面的例子:

假設有一顆樹有 5 個節點,四條邊依次爲:(1, 2), (1, 3), (2, 4), (2, 5),以下圖所示:

第 1 步,選取具備最小標號的葉子節點 3,將與它相連的點 1 做爲第 1 個 Purfer Number,並從樹中刪掉節點 3:

第 2 步,選取最小標號的葉子節點 1,將與其相連的點 2 做爲第 2 個 Purfer Number,並從樹中刪掉點 1:

第 3 步,選取最小標號的葉子節點 4,將與其相連的點 2 做爲第 3 個 Purfer Number,並從樹中刪掉點 4:

最後,咱們獲得的 Purfer Sequence 爲:1 2 2

不難看出,上面的步驟獲得的 Purfer Sequence 具備惟一性,也就是說,一個樹,只能獲得一個惟一的 Purfer Sequence

 

接下來看,怎麼由一個 Purfer Sequence 獲得一個樹

由 Purfer Sequence 獲得一棵樹,先將全部編號爲 1 到 n 的點的度賦初值爲 1,而後加上它在 Purfer Sequence 中出現的次數,獲得每一個點的度

先執行 n-2 步,每一步,選取具備最小標號的度爲 1 的點 u 與 Purfer Sequence 中的第 i 個數 v 表示的頂點相連,獲得樹中的一條邊,並將 u 和 v 的度減一

最後再把剩下的兩個度爲 1 的點連邊,加入到樹中

 

咱們能夠根據上面的例子獲得的 Purfer Sequence :1 2 2 從新獲得一棵樹

Purfer Sequence 中共有 3 個數,能夠知道,它表示的樹中共有 5 個點,按照上面的方法計算他們的度爲下表所示:

 

頂點 1 2 3 4 5
2 3 1 1 1

 

 

 

第 1 次執行,選取最小標號度爲 1 的點 3 和 Purfer Sequence 中的第 1 個數 1 連邊:

將 1 和 3 的度分別減一:

 

頂點 1 2 3 4 5
1 3 0 1 1

 

 

 

第 2 次執行,選取最小標號度爲 1 的點 1 和 Purfer Sequence 中的第 2 個數 2 連邊:

將 1 和 2 的度分別減一:

 

頂點 1 2 3 4 5
0 2 0 1 1

 

 

 

第 3 次執行,將最小標號度爲 1 的點 4 和 Purfer Sequence 第 3 個數 2 連邊:

將 2 和 4 的度分別減一:

 

頂點 1 2 3 4 5
0 1 0 0 1

 

 

 

最後,還剩下兩個點 2 和 5 的度爲 1,連邊:

至此,一個 Purfer Sequence 獲得的樹畫出來了,由上面的步驟可知,Purfer Sequence 和一個樹惟一對應

綜上,一個 Purfer Sequence 和一棵樹一一對應

 

有了 Purfer Sequence 的知識,這題怎麼搞定呢?

 

先不考慮無解的狀況,從 Purfer Sequence 構造樹的過程當中可知,一個點的度數減一表示它在 Purfer Sequence 中出現了幾回,那麼:

假設度數有限制的點的數量爲 cnt,他們的度數分別爲:d[i]

另:

 

那麼,在 Purfer Sequence 中的不一樣排列的總數爲:

而剩下的 n-2-sum 個位置,能夠隨意的排列剩餘的 n-cnt 個點,因而,總的方案數就應該是:

化簡以後爲:

在有解的狀況下,計算該結果輸出就好了

無解的狀況很是好肯定,這裏就再討論了

 

參考代碼

 

 1 import java.util.*;
 2 import java.math.*;
 3 
 4 public class Main {
 5     static int n, d[]=new int[10002];
 6     static BigInteger p[]=new BigInteger[1002];
 7     static BigInteger ans;
 8     
 9     static public void main(String args[]) {
10         Scanner IN=new Scanner(System.in);
11         n=IN.nextInt();
12         int sum=0, flag=0, cnt=0;
13         for(int i=0; i<n; i++) {
14             d[i]=IN.nextInt();
15             if(d[i]==0 || d[i]>n-1) flag=1;
16             if(d[i]==-1) continue;
17             sum+=d[i]-1;
18             cnt++;
19         }
20         IN.close();
21         if(n==1) {
22             if(d[0]==0 || d[0]==-1) System.out.println(1);
23             else System.out.println(0);
24             return;
25         }
26         if(n==2) {
27             if((d[0]==-1 || d[0]==1) && (d[1]==-1 || d[1]==-1)) System.out.println(1);
28             else System.out.println(0);
29             return;
30         }
31         if(flag==1) System.out.println(0);
32         p[0]=BigInteger.ONE;
33         for(int i=1; i<=n; i++) p[i]=p[i-1].multiply(BigInteger.valueOf(i));
34         ans=p[n-2].divide(p[n-2-sum]);
35         for(int i=0; i<n; i++) {
36             if(d[i]==-1) continue;
37             ans=ans.divide(p[d[i]-1]);
38         }
39         for(int i=0; i<n-2-sum; i++) ans=ans.multiply(BigInteger.valueOf(n-cnt)); 
40         System.out.println(ans);
41     }
42 }
BZOJ 1005

 

題目連接 & AC 通道

 

BZOJ 1005 [HNOI2008] 明明的煩惱

相關文章
相關標籤/搜索