Nhảy chuyển đến

Prüfer danh sách

Note

Bổn văn phiên dịch tựe-maxx Prüfer Code.Mặt khác giải thích một chút, nguyên văn giao điểm là từBắt đầu cấp, bổn văn dựa theo đại đa số người thói quen đổi thành từCấp.

Áng văn chương này giới thiệu Prüfer danh sách (Prüfer code), đây là một loại đem mang cấp thụ dùng một cái duy nhất số nguyên danh sách tỏ vẻ phương pháp.

Sử dụng Prüfer danh sách có thể chứng minhKhải lai công thức(Cayley's formula). Hơn nữa chúng ta cũng sẽ giảng giải như thế nào tính toán ở một cái đồ trung thêm biên sử đồ liên thông phương án số.

Chú ý:Chúng ta không suy xét đựngCái giao điểm thụ.

Prüfer danh sách

Dẫn vào

Prüfer danh sách có thể đem một cái mang cấpCái giao điểm thụ dùngTrungCái số nguyên tỏ vẻ. Ngươi cũng có thể đem nó lý giải vì hoàn toàn đồ sinh thành thụ cùng dãy số chi gian song bắn. Thường dùng tổ hợp đếm hết vấn đề trung.

Heinz Prüfer với 1918 năm phát minh cái này danh sách tới chứng minhKhải lai công thức.

Đối thụ thành lập Prüfer danh sách

Prüfer là như thế này thành lập: Mỗi lần lựa chọn một cái đánh số nhỏ nhất diệp giao điểm cũng xóa rớt nó, sau đó ở danh sách trung ký lục hạ nó liên tiếp đến cái kia giao điểm. Lặp lạiThứ sau cũng chỉ dư lại hai cái giao điểm, thuật toán kết thúc.

Hiển nhiên sử dụng đôi có thể làm đượcPhức tạp độ

Thực hiện
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// số hiệu trích tự nguyên văn, giao điểm là từ 0 cấp
vectorvectorint>>adj;

vectorint>pruefer_code(){
intn=adj.size();
setint>leafs;
vectorint>degree(n);
vectorbool>killed(n);
for(inti=0;in;i++){
degree[i]=adj[i].size();
if(degree[i]==1)leafs.insert(i);
}

vectorint>code(n-2);
for(inti=0;in-2;i++){
intleaf=*leafs.begin();
leafs.erase(leafs.begin());
killed[leaf]=true;
intv;
for(intu:adj[leaf])
if(!killed[u])v=u;
code[i]=v;
if(--degree[v]==1)leafs.insert(v);
}
returncode;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# giao điểm là từ 0 cấp
adj=[[]]


defpruefer_code():
n=len(adj)
leafs=set()
degree=[0]*n
killed=[False]*n
foriinrange(1,n):
degree[i]=len(adj[i])
ifdegree[i]==1:
leafs.intersection(i)
code=[0]*(n-2)
foriinrange(1,n-2):
leaf=leafs[0]
leafs.pop()
killed[leaf]=True
foruinadj[leaf]:
ifkilled[u]==False:
v=u
code[i]=v
ifdegree[v]==1:
degree[v]=degree[v]-1
leafs.intersection(v)
returncode

Tỷ như, đây là một cây 7 cái giao điểm thụ Prüfer danh sách xây dựng quá trình:

Prüfer

Cuối cùng danh sách chính là.

Đương nhiên, cũng có một cái tuyến tính cấu tạo thuật toán.

Prüfer danh sách tuyến tính cấu tạo thuật toán

Tuyến tính cấu tạo bản chất chính là giữ gìn một cái kim đồng hồ chỉ hướng chúng ta sắp sửa xóa bỏ giao điểm. Đầu tiên phát hiện, diệp giao điểm số thị phi nghiêm khắc đơn điệu giảm dần, xóa đi một cái diệp giao điểm, diệp giao điểm tổng số hoặc là bất biến hoặc là giảm 1.

Vì thế chúng ta suy xét như vậy một cái quá trình: Giữ gìn một cái kim đồng hồ.Mới bắt đầu khiChỉ hướng đánh số nhỏ nhất diệp giao điểm. Đồng thời chúng ta giữ gìn mỗi cái giao điểm số độ, phương tiện chúng ta biết ở xóa bỏ giao điểm khi hầu hay không sinh ra tân diệp giao điểm. Thao tác như sau:

  1. Xóa bỏChỉ hướng giao điểm, cũng kiểm tra hay không sinh ra tân diệp giao điểm.
  2. Nếu sinh ra tân diệp giao điểm, giả thiết đánh số vì,Chúng ta tương đốiLớn nhỏ quan hệ. Nếu,Như vậy không làm mặt khác thao tác; nếu không liền lập tức xóa bỏ,Sau đó kiểm tra xóa bỏSau hay không sinh ra tân diệp giao điểm, lặp lạiBước đi, thẳng đến chưa sinh ra tân tiết điểm hoặc là tân tiết điểm đánh số.
  3. Làm kim đồng hồTự tăng thẳng đến gặp được một cái chưa bị xóa bỏ diệp giao điểm mới thôi;

Chính xác tính

Tuần hoàn kể trên thao tácThứ, liền hoàn thành danh sách cấu tạo. Kế tiếp suy xét thuật toán chính xác tính.

Là trước mặt đánh số nhỏ nhất diệp giao điểm, nếu xóa bỏSau chưa sinh ra diệp giao điểm, chúng ta cũng chỉ có thể đi tìm kiếm tiếp theo cái diệp giao điểm; nếu sinh ra diệp giao điểm:

  • Nếu,Tắc dù saoSau này rà quét đều sẽ quét đến nó, vì thế không làm thao tác;
  • Nếu,Bởi vìNguyên bản chính là đánh số nhỏ nhất, màSoCòn nhỏ, cho nênChính là trước mặt đánh số nhỏ nhất diệp giao điểm, ưu tiên xóa bỏ. Xóa bỏTiếp tục như vậy suy xét thẳng đến không có càng tiểu nhân diệp giao điểm.

Thuật toán phức tạp độ phân tích, phát hiện mỗi điều biên nhiều nhất bị phỏng vấn một lần ( ở xóa số độ khi hầu ), mà kim đồng hồ nhiều nhất biến lịch mỗi cái giao điểm một lần, bởi vậy phức tạp độ là.

Thực hiện

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// từ nguyên văn trích số hiệu, đồng dạng lấy 0 vì khởi điểm
vectorvectorint>>adj;
vectorint>parent;

voiddfs(intv){
for(intu:adj[v]){
if(u!=parent[v])parent[u]=v,dfs(u);
}
}

vectorint>pruefer_code(){
intn=adj.size();
parent.resize(n),parent[n-1]=-1;
dfs(n-1);

intptr=-1;
vectorint>degree(n);
for(inti=0;in;i++){
degree[i]=adj[i].size();
if(degree[i]==1&&ptr==-1)ptr=i;
}

vectorint>code(n-2);
intleaf=ptr;
for(inti=0;in-2;i++){
intnext=parent[leaf];
code[i]=next;
if(--degree[next]==1&&nextptr){
leaf=next;
}else{
ptr++;
while(degree[ptr]!=1)ptr++;
leaf=ptr;
}
}
returncode;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# đồng dạng lấy 0 vì khởi điểm
adj=[[]]
parent=[0]*n

defdfs()v:
foruinadj[v]:
ifu!=parent[v]:
parent[u]=v
dfs(u)

defpruefer_code():
n=len(adj)
parent[n-1]=-1
dfs(n-1)

ptr=-1
degree=[0]*n
foriinrange(0,n):
degree[i]=len(adj[i])
ifdegree[i]==1andptr==-1:
ptr=i

code=[0]*(n-2)
leaf=ptr
foriinrange(0,n-2):
next=parent[leaf]
code[i]=next
ifdegree[next]==1andnextptr:
degree[next]=degree[next]-1
leaf=next
else:
ptr=ptr+1
whiledegree[ptr]!=1:
ptr=ptr+1
leaf=ptr
returncode

Prüfer danh sách tính chất

  1. Ở cấu tạo xong Prüfer danh sách sau nguyên thụ trung sẽ dư lại hai cái giao điểm, trong đó một cái nhất định là đánh số lớn nhất điểm.
  2. Mỗi cái giao điểm ở danh sách trung xuất hiện số lần là này số độ giảm.( không có xuất hiện chính là diệp giao điểm )

Dùng Prüfer danh sách trùng kiến thụ

Trùng kiến thụ phương pháp là cùng loại. Căn cứ Prüfer danh sách tính chất, chúng ta có thể được đến nguyên trên cây mỗi cái điểm số độ. Sau đó ngươi cũng có thể được đến đánh số nhỏ nhất diệp giao điểm, mà cái này giao điểm nhất định cùng Prüfer danh sách cái thứ nhất số liên tiếp. Sau đó chúng ta đồng thời xóa rớt này hai cái giao điểm số độ.

Giảng đến nơi đây có lẽ ngươi đã biết nên làm như thế nào. Mỗi lần chúng ta lựa chọn một cái số độ vìNhỏ nhất giao điểm đánh số, cùng trước mặt cái giơ lên Prüfer danh sách điểm liên tiếp, sau đó đồng thời trừ hai cái điểm độ. Đến cuối cùng chúng ta dư lại hai cái số độ vìĐiểm, trong đó một cái là giao điểm.Liền đem chúng nó thành lập liên tiếp. Sử dụng đôi giữ gìn cái này quá trình, ở giảm số độ trong quá trình nếu phát hiện số độ giảm đếnLiền đem cái này giao điểm tăng thêm đến đôi trung, làm như vậy phức tạp độ là.

Thực hiện
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// nguyên văn trích số hiệu
vectorpairint,int>>pruefer_decode(vectorint>const&code){
intn=code.size()+2;
vectorint>degree(n,1);
for(inti:code)degree[i]++;

setint>leaves;
for(inti=0;in;i++)
if(degree[i]==1)leaves.insert(i);

vectorpairint,int>>edges;
for(intv:code){
intleaf=*leaves.begin();
leaves.erase(leaves.begin());

edges.emplace_back(leaf,v);
if(--degree[v]==1)leaves.insert(v);
}
edges.emplace_back(*leaves.begin(),n-1);
returnedges;
}

Tuyến tính thời gian trùng kiến thụ

Cùng tuyến tính cấu tạo Prüfer danh sách phương pháp. Ở xóa số độ khi hầu sẽ sinh ra tân diệp giao điểm, vì thế phán đoán cái này diệp giao điểm cùng kim đồng hồLớn nhỏ quan hệ, nếu càng tiểu liền ưu tiên suy xét nó.

Thực hiện

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// nguyên văn trích số hiệu
vectorpairint,int>>pruefer_decode(vectorint>const&code){
intn=code.size()+2;
vectorint>degree(n,1);
for(inti:code)degree[i]++;

intptr=0;
while(degree[ptr]!=1)ptr++;
intleaf=ptr;

vectorpairint,int>>edges;
for(intv:code){
edges.emplace_back(leaf,v);
if(--degree[v]==1&&vptr){
leaf=v;
}else{
ptr++;
while(degree[ptr]!=1)ptr++;
leaf=ptr;
}
}
edges.emplace_back(leaf,n-1);
returnedges;
}

Thông qua này đó quá trình kỳ thật có thể lý giải, Prüfer danh sách cùng mang cấp vô căn thụ thành lập song bắn quan hệ.

Cayley công thức (Cayley's formula)

Hoàn toàn đồCây sinh thành thụ.

Như thế nào chứng minh? Phương pháp rất nhiều, nhưng là dùng Prüfer danh sách chứng là rất đơn giản. Tùy ý một cái chiều dài vìGiá trị vựcSố nguyên danh sách đều có thể thông qua Prüfer danh sách song bắn đối ứng một cái sinh thành thụ, vì thế phương án số chính là.

Đồ liên thông phương án số

Prüfer danh sách khả năng so ngươi nghĩ đến còn cường đại. Nó có thể sáng tạo soKhải lai công thứcCàng thông dụng công thức. Tỷ như dưới vấn đề:

Một cáiCái điểmĐiều biên mang cấp vô hướng đồ cóCái liên thông khối. Chúng ta hy vọng tăng thêmĐiều biên khiến cho toàn bộ đồ liên thông. Cầu phương án số.

Chứng minh

ThiếtTỏ vẻ mỗi cái liên thông khối số lượng. Chúng ta đốiCái liên thông khối cấu tạo Prüfer danh sách, sau đó ngươi phát hiện này cũng không phải bình thường Prüfer danh sách. Bởi vì mỗi cái liên thông khối liên tiếp phương pháp rất nhiều. Không thể trực tiếp cam liền thiết a. Vì thế thiếtVì đệCái liên thông khối số độ. Bởi vì số độ chi cùng là biên số gấp hai, vì thế.Tắc đối với cấp địnhDanh sách cấu tạo Prüfer danh sách phương án số là

Đối với đệCái liên thông khối, nó liên tiếp phương thức cóLoại, bởi vậy đối với cấp địnhDanh sách sử đồ liên thông phương án số là

Hiện tại chúng ta muốn cái cửDanh sách, tư thế biến thành

,

Tốt đây là một cái phi thường không mừng nghe nhạc thấy tư thế. Nhưng là đừng hoảng hốt! Chúng ta có bao nhiêu nguyên Định lý nhị thức:

Như vậy chúng ta đối nguyên thức làm một chút đổi nguyên, thiết,Hiển nhiên,Vì thế nguyên thức biến thành

,

Hóa giản được đến

Tức

Đây là đáp án lạp

Bài tập