// 代码摘自原文,结点是从 0 标号的vector<vector<int>> adj;vector<int> pruefer_code() { int n = adj.size(); set<int> leafs; vector<int> degree(n); vector<bool> killed(n); for (int i = 0; i < n; i++) { degree[i] = adj[i].size(); if (degree[i] == 1) leafs.insert(i); } vector<int> code(n - 2); for (int i = 0; i < n - 2; i++) { int leaf = *leafs.begin(); leafs.erase(leafs.begin()); killed[leaf] = true; int v; for (int u : adj[leaf]) if (!killed[u]) v = u; code[i] = v; if (--degree[v] == 1) leafs.insert(v); } return code;}
Python
# 结点是从 0 标号的adj = [[]]def pruefer_code(): n = len(adj) leafs = set() degree = [0] * n killed = [False] * n for i in range(1, n): degree[i] = len(adj[i]) if degree[i] == 1: leafs.intersection(i) code = [0] * (n - 2) for i in range(1, n - 2): leaf = leafs[0] leafs.pop() killed[leaf] = True for u in adj[leaf]: if killed[u] == False: v = u code[i] = v if degree[v] == 1: degree[v] = degree[v] - 1 leafs.intersection(v) return code
// 从原文摘的代码,同样以 0 为起点vector<vector<int>> adj;vector<int> parent;void dfs(int v) { for (int u : adj[v]) { if (u != parent[v]) parent[u] = v, dfs(u); }}vector<int> pruefer_code() { int n = adj.size(); parent.resize(n), parent[n - 1] = -1; dfs(n - 1); int ptr = -1; vector<int> degree(n); for (int i = 0; i < n; i++) { degree[i] = adj[i].size(); if (degree[i] == 1 && ptr == -1) ptr = i; } vector<int> code(n - 2); int leaf = ptr; for (int i = 0; i < n - 2; i++) { int next = parent[leaf]; code[i] = next; if (--degree[next] == 1 && next < ptr) { leaf = next; } else { ptr++; while (degree[ptr] != 1) ptr++; leaf = ptr; } } return code;}
Python
# 同样以 0 为起点adj = [[]]parent = [0] * ndef dfs(v): for u in adj[v]: if u != parent[v]: parent[u] = v dfs(u)def pruefer_code(): n = len(adj) parent[n - 1] = -1 dfs(n - 1) ptr = -1 degree = [0] * n for i in range(0, n): degree[i] = len(adj[i]) if degree[i] == 1 and ptr == -1: ptr = i code = [0] * (n - 2) leaf = ptr for i in range(0, n - 2): next = parent[leaf] code[i] = next if degree[next] == 1 and next < ptr: degree[next] = degree[next] - 1 leaf = next else: ptr = ptr + 1 while degree[ptr] != 1: ptr = ptr + 1 leaf = ptr return code
一个 n 个点 m 条边的带标号无向图有 k 个连通块。我们希望添加 k−1 条边使得整个图连通。求方案数。
证明
设 si 表示第 i 个连通块内点的数量。我们考虑对 k 个连通块构造 Prüfer 序列。由于两个连通块之间的连接方法很多,这并不是普通的 Prüfer 序列。于是不妨假设 di 为第 i 个连通块的度数。由于度数之和是边数的两倍,于是 ∑i=1kdi=2k−2。则对于给定的 d 序列构造 Prüfer 序列的方案数是