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


 

題目大意

 

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

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

 

Input

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

Output

  一個整數,表示不同的滿足要求的樹的個數,無解輸出 0

 

做法分析

 

這題需要了解一種數列: Purfer Sequence

我們知道,一棵樹可以用括號序列來表示,但是,一棵頂點標號(1~n)的樹,還可以用一個叫做 Purfer Sequence 的數列表示

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

 

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

 

先看看怎么由一個樹得到 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] 明明的煩惱

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM