prufer序列學習筆記

可以用於處理一類有關生成樹計數類的問題。

prufer序列是有關無根樹的序列,並且n點無根樹能唯一對應n-2長度的prufer序列。

一、prufer序列生成方法:

把無根樹裏所有度數爲1的點定義爲葉子,重複執行以下操作直至原樹裏只剩下兩個節點:選取當前標號最小的葉子,把它的父親接在當前生成的prufer序列末尾,並在原樹裏刪除該點。

二、prufer序列還原無根樹:

設一個點集V={1,2,3,...,n},然後重複執行以下操作,取出prufer序列當前開頭元素x,然後在V中從左到右遍歷找到第一個沒有在當前prufer序列中出現的元素y,並把x、y連一條邊,然後prufer序列刪除開頭x,點集V刪除y。直到V中剩下兩個點時,把這兩個點連一條邊,至此,原樹還原完成。

實現生成還原的代碼可以參看這位大佬博客:https://blog.csdn.net/morejarphone/article/details/50677172

三、性質

1.從上面的生成還原看,prufer序列內每個點取值都可以在[1,n]內,這樣可以證明一個n個點的完全圖生成的無根樹數量爲n^(n-2)

2.可以發現每個點在prufer序列每出現一次就對應了一個與它相連的點的刪除,所以prufer序列中某點出現次數等於該點在原樹上的度數減一。

3.依據上面第二條性質,假設給定樹上每個節點度數,可以發現生成樹個數就是一個含重複元素的集合的排列數,就是階乘除以一堆階乘積的東西...

四、模板題

HNOI2004-樹的計數

鏈接:https://www.luogu.org/problemnew/show/P2290

注意判等於0的一些情況。(度數爲0而點數大於1)

代碼:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=160;

ll ans=1;
int n,d[N],tax[N*N],tnum=0;

int gcd(int x,int y)
{return !y?x:gcd(y,x%y);}

int main()
{
    int sum=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&d[i]),--d[i],sum+=d[i];
        if(d[i]<0&&n!=1)return puts("0"),0;
        for(int j=2;j<=d[i];j++)
            tax[++tnum]=j;
    }
    if(sum!=n-2)return puts("0"),0;
    for(int i=2,nw;i<=n-2;i++)
    {
        nw=i;
        for(int j=1,tmp;j<=tnum;j++)
        {
            if(tax[j]==1)continue;
            tmp=gcd(nw,tax[j]);
            nw/=tmp,tax[j]/=tmp;
        }
        ans=ans*nw;
    }
    printf("%lld\n",ans);
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章