1. 程式人生 > 實用技巧 >樹的基礎:樹的重心

樹的基礎:樹的重心

Dev.c++樹的基礎:樹是一種特殊的圖,有一些特殊的性質,重心就是其一。可以用它的定義求解。

宣告:感謝oi-wiki所提供的程式碼。在下***進行了一點點修改。這裡先貼出oi-wiki提供的原始碼。

宣告:感謝大佬zhnzh提供的幫助。一些用詞和技術方面是它所提供的。若有出錯,請在評論區提出

再次宣告:如果有錯,不要怪我喲不要臉的

// 這份程式碼預設節點編號從 1 開始,即 i ∈ [1,n]
int size[MAXN],  // 這個節點的“大小”(所有子樹上節點數 + 該節點)
    weight[MAXN],  // 這個節點的“重量”
    centroid[2];   // 用於記錄樹的重心(存的是節點編號)
void GetCentroid(int cur, int fa) {  // cur 表示當前節點 (current)
  size[cur] = 1;
  weight[cur] = 0;
  for (int i = head[cur]; i != -1; i = e[i].nxt) {
    if (e[i].to != fa) {  // e[i].to 表示這條有向邊所通向的節點。
      GetCentroid(e[i].to, cur);
      size[cur] += size[e[i].to];
      weight[cur] = max(weight[cur], size[e[i].to]);
    }
  }
  weight[cur] = max(weight[cur], n - size[cur]);
  if (weight[cur] <= n / 2) {  // 依照樹的重心的定義統計
    centroid[centroid[0] != 0] = cur;
  }
}

同時貼出我講解所需的程式碼

int size[MAXN],  // 這個節點的“大小”(所有子樹上節點數 + 該節點)
    weight[MAXN],  // 記錄最大子樹 
    centroid[2];   // 用於記錄樹的重心(存的是節點編號)
void GetCentroid(int u, int fa) {  // u 表示當前節點 (current)
	size[u] = 1;
	weight[u] = 0;
	for (int i = head[u]; i != -1; i = e[i].nxt) {
		if (e[i].to != fa) {  // e[i].to 表示這條有向邊所通向的節點。
      		GetCentroid(e[i].to, u);
      		size[u] += size[e[i].to];
      		weight[u] = max(weight[u], size[e[i].to]);
    	}
    }
    weight[u] = max(weight[u], n - size[u]);
	if (weight[u] <= n / 2) {  // 依照樹的重心的定義統計
		centroid[centroid[0] != 0] = u;
  	}
}

因為對於樹上的每一個點,計算其所有子樹中最大的子樹節點數,這個值最小的點就是這棵樹的重心;
所以這裡利用這個計算重心。
這裡先將整棵樹遍歷一遍,遍歷過程中,每個節點利用遞迴將它的子樹遞迴出來(至於怎麼弄得等會解釋)。
然後算出這棵樹上最大的子樹,不斷的更新它的重心就可以了。
這裡要重點解釋一下遞迴求解子樹大小。