日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Prufer 序列

發布時間:2023/12/3 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Prufer 序列 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Prufer 序列

定義與建立

Prufer 序列可以將一個帶標號 \(n\) 個結點的樹用 \([1,n]\) 中的 \(n-2\) 個整數表示。一個無向帶標號生成樹與數列之間的雙射。

對于一棵樹,每次我們選擇它編號最小葉子結點,刪除它并記錄下與它相連的節點的編號,那么最終記錄下的 \(n-2\) 個數就組成了這棵樹的 Prufer 序列。

顯然用這個東西維護樹的結構感覺非常不好,這個東西主要用來數數用的。

對樹建立 Prufer 序列

按照定義直接建立,那么每次從堆中取出最小的數,刪去它并記錄。

這樣可以得到一個 \(\mathcal{O(n\log n)}\) 的做法,但是顯然這不夠優美,我們需要一個 \(\mathcal{O(n)}\) 的解法。

我們發現剩余的葉子結點數量是遞減的,每次刪除要么少一個,要么少一個又多一個。

從小到大枚舉編號 \(p\),如果是葉子結點,將和它們相鄰的點放入 Prufer 序列中??紤]這個葉子結點帶來的新葉子結點:

  • 如果和它相鄰的點編號 \(p'>p\) 或者 \(p'\) 沒有變成葉子結點,那么不用管,它會在之后被枚舉到。
  • 但是如果 \(p'<p\),它在時候不會被枚舉到了。但是發現刪除之前當前最小的葉子結點是 \(p\),所以刪后 \(p'\) 必然是最小的葉子,所以可以直接繼續刪除 \(p'\)。
for(int i=1,x;i<n;i++) x=rd(),add(i,x),add(x,i),ind[i]++,ind[x]++; // [1,n-1] 的父親序列 for(int i=1;i<=n;i++) if(ind[i]==1) exist[i]=true; for(int i=1,p;i<=n;i++) {if(!exist[i]) continue;p=i;while(p<=i){used[p]=true;for(int j=hea[p];j;j=nex[j])if(!used[ver[j]]) { p=ver[j]; break; }if(ind[p]==1) break;ind[p]--,pru[++cnt]=p;if(ind[p]==1) exist[p]=true;if(ind[p]!=1 || p>i) break;}if(ind[p]==1) exist[p]=true; } assert(cnt==n-2); for(int i=1;i<=cnt;i++) ret^=1ll*i*pru[i]; printf("%lld\n",ret);

用 Prufer 還原無根樹

發現 Prufer 序列中的每個數的出現次數就是原樹中每個點的度數 \(-1\),可以每次連一個葉子結點重構。

方法類似,一個暴力的做法是每次選出最小的當前的葉子結點,將它與 Prufer 序列最前面的元素相連,這樣復雜度是 \(\mathcal{O(n\log n)}\) 的。

發現葉子結點編號遞增,設刪去的葉子結點為 \(p\),和它相鄰的是 \(p'\)。當加完 \(p\)\(p'\) 的度數變為 \(1\) 并且 \(p'<p\),那么它下一次一定被選擇,直接繼續連邊即可。

for(int i=1;i<=n-2;i++) pru[i]=rd(),ind[pru[i]]++; for(int i=1;i<=n;i++) if(!ind[i]) exist[i]=true; int pos=1; for(int i=1,p;i<=n;i++) {if(!exist[i]) continue;p=i;while(p<=i){if(pos==n-1) { fa[p]=n; break; }fa[p]=pru[pos],p=pru[pos],ind[p]--,pos++;if(pos>=n) break;if(ind[p] || p>i) break;}if(!ind[p]) exist[p]=true; } for(int i=1;i<n;i++) ret^=1ll*i*fa[i]; printf("%lld\n",ret);

主要性質

  • Prufer 序列與無根樹一一對應(好像比較顯然)

  • 度數為 \(d_i\) 的點在 Prufer 序列中出現 \(d_i-1\) 次(上面還用到了這個結論)

  • 【根據度數求方案】對于給定每個點度數為 \(d_i\) 的無根樹,方案數為:

    \[\dfrac{(n-2)!}{\prod_{i=1}^{n}(d_i-1)!} \]

    證明:Prufer 序列長度為 \(n-2\),每個數出現次數為 \(d_i-1\),根據組合意義直接計算全排列即可。

  • 【根據連通塊數量與大小求方案】一個 \(n\) 個點 \(m\) 條邊的帶標號無向圖有 \(k\) 個連通塊,每個連通塊大小為 \(s_i\),需要增加 \(k-1\) 條邊使得整個圖聯通,方案數為:(但是當 \(k=1\) 時需要特判)

    \[n^{k-2}\cdot\prod_{i=1}^{k}s_i \]

    證明見 OI-wiki

總結

以上是生活随笔為你收集整理的Prufer 序列的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。