AcWing 846 樹的重心

2022-09-24 16:12:13 字數 1859 閱讀 1227

目錄dfs演算法求解

參考文章

給定一顆樹,樹中包含 n 個結點(編號 1∼n)和 n−1 條無向邊。

請你找到樹的重心,並輸出將重心刪除後,剩餘各個連通塊中點數的最大值。

重心定義:重心是指樹中的乙個結點,如果將這個點刪除後,剩餘各個連通塊中點數的最大值最小,那麼這個節點被稱為樹的重心。

輸入格式

第一行包含整數 nn,表示樹的結點數。

接下來 n−1 行,每行包含兩個整數 a 和 b,表示點 a 和點 b 之間存在一條邊。

輸出格式

輸出乙個整數 m,表示將重心刪除後,剩餘各個連通塊中點數的最大值。

資料範圍

1≤n≤105

輸入樣例

9

1 21 7

1 42 8

2 54 3

3 94 6

輸出樣例:
4
首先使用陣列模擬鍊錶建立無向圖,注意,因為是無向圖,所以邊的數目應該開成點數目的兩倍然後使用dfs遍歷圖,dfs(u)返回的是以u為根節點的子樹中節點的數目(包括u本身)

使用sum表示以u為根的子樹的大小,使用size表示每個節點u刪除後,剩餘聯通塊中節點數目的最大值,則分兩部分看

對於u的所有孩子節點(在u的列表中,並且還沒有被訪問過的節點)j:用對j進行dfs(j)得到該子樹的大小s,遍歷所有節點求出size = max(s)

對u的父節點所在的連通塊:其大小為n - sum

所以size = max(size, n-sum)

每次遍歷所有u的孩子節點結束後,得到刪除節點u之後,剩餘連通塊中節點數目的最大值:size

那麼只需要維護乙個全域性變數ans,求得所有節點size的最小值 :ans = min(ans, size)

如圖,從1開始遍歷,當u=4這個節點的時候

其孩子子樹大小分別為:2(3-9), 1(6)

其父節點所在的子樹大小為:n-sum = 9 - 4 = 5 (1-2-8-5-7)

所以刪除u之後剩餘連通塊中點的數目的最大值為:size = 5

遍歷所有點的size就可得到最後的結果

#include#include#include#includeusing namespace std;

const int n = 100010;

// 存圖

int h[n], e[2*n], ne[2*n], idx = 0;

bool state[n]; // 標記每個點是否被訪問過

int n;

int ans = n; // 最後的結果

// 建邊

void add(int a, int b)

// 返回以u為根的子樹的大小,包含u

int dfs(int u)

} size = max(size, n - sum); //再看一眼u的父節點所在的子樹大小n-sum

ans = min(ans, size);

return sum;

}int main()

// state[1] = true;

dfs(1);

cout << ans << endl;

return 0;

}

\(o(m+n)\)

AcWing 846 樹的重心

大佬的題解 題目鏈結 這道題給的標籤竟然是 樹與圖的深度優先遍歷 這是神馬玩意,然後我點進去看了一下,果然還是沒有思路,然後看了y總,如願以償,y總yyds,我看懂了,然後我就認真再看了一遍題。我覺得好像是求子樹問題,然後我就有了思路。大佬的題解其實講的很清楚,最主要的是靠自己的想象,最關鍵的幾個變...

ACWing846 樹的重心

dfs,一次遍歷,求出每個結點去除該點後的最大連通塊的個數,同時更新ans 全域性變數存放最終結果 1 include2 include3 include4 using namespace std 56 const int n 100010 7 int h n e n 2 ne n 2 idx 樹為...

AcWing 846 樹的重心

給定一顆樹,樹中包含n個結點 編號1 n 和n 1條無向邊。請你找到樹的重心,並輸出將重心刪除後,剩餘各個連通塊中點數的最大值。重心定義 重心是指樹中的乙個結點,如果將這個點刪除後,剩餘各個連通塊中點數的最大值最小,那麼這個節點被稱為樹的重心。輸入格式 第一行包含整數n,表示樹的結點數。接下來n 1...