【模板】樹的重心
阿新 • • 發佈:2019-02-11
樹的重心
定義:找到一個點,其所有的子樹中最大的子樹節點數最少,那麼這個點就是這棵樹的重心,刪去重心後,生成的多棵樹儘可能平衡。
演算法流程
首先,利用前向星存邊建立邊表。由於無向,所以要連兩次邊。我們用一次 建立以1為根節點時每個結點所在子樹的結點數。
接下來考慮把這個點刪掉的結果,如果一個非根結點有 個兒子,那麼刪掉這個點之後會有 個連通分量,因為這個結點不是根節點,那麼除了這個結點及它的所有子樹外還有一個連通分量,我們將之稱為這個結點的上方子樹。接下來,計算這些子樹(包括上方子樹)的 再從中找個最大值,因為總共有 個結點所以有 個最大值,接下來在其中挑一個最小的即可,當這個值取到最小時的那個結點就是這棵樹的重心。
的計算方法:
- 結點 的子樹,直接利用 即可。
- 結點 的上方子樹,可以利用求補集的思想,總共有 個結點,這個結點及其所有子樹的結點和為 , 那麼它的上方子樹的 就是 。
上述的計算過程都在 中執行完成,故時間複雜度和空間複雜度均為
程式碼:
struct Tree {
struct edgetype {
int to, next;
};
int n, root, maxsize;
std::vector< edgetype > edge;
std::vector< int > head, size;
Tree() : edge(0), head(0), size(0) {}
Tree(int n) : n(n), head(n + 1, -1), size(n + 1) {}
inline void AddEdge(int from, int to) {
edge.push_back((edgetype){to, head[from]});
head[from] = edge.size() - 1 ;
}
void center(int u, int p) {
size[u] = 1;
int ret = 0;
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if (v == p) continue;
center(v, u);
size[u] += size[v];
ret = std::max(ret, size[v]);
}
ret = std::max(ret, n - size[u]);
if (ret < maxsize) {
maxsize = ret;
root = u;
}
}
};