# 【CSES】1131. Tree Diameter
## [題目連結](https://cses.fi/problemset/task/1131)
## **時間複雜度**
* Tree DP: $O(N)$
* Tree DFS: $O(N)$
## **1. Tree DP 解題想法**
如果我們要使用動態規劃的話,首先要先定義出動態規劃的基底、狀態跟轉移如下:
設 $f$ 為任意節點,$c$ 為 $f$ 的任意子節點,$l$ 為任意葉節點
* 基底:
* $dp[l][1]$ = 0
* $dp[l][2]$ = 0
* 狀態:
* $dp[f][1]$ 代表此節點最長路徑的長度
* $dp[f][2]$ 代表此節點次長路徑的長度
* 轉移:
* 如果 $dp[c][1] + 1 > dp[f][1]$
* $dp[f][2] = dp[f][1]$
* $dp[f][1] = dp[c][1] + 1$
* 如果 $dp[f][1] > dp[c][1] + 1$ 且 $dp[c][1] + 1 > dp[f][2]$
* $dp[f][2] = dp[c][1] + 1$
因此最終的答案就會是 $res = max( dp[f][0] + dp[f][1] )$
## **1. Tree DP 完整程式**
```cpp=
/* Question : CSES 1131. Tree Diameter */
/***** 2. Tree DP Solution *****/
#include<bits/stdc++.h>
using namespace std;
#define opt ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define priq(type) priority_queue<type, vector<type>, greater<type>>
#define mem(x, value) memset(x, value, sizeof(x));
#define pii pair<int, int>
#define pdd pair<double, double>
#define pb push_back
#define f first
#define s second
#define int long long
const auto dir = vector< pair<int, int> > { {1, 0}, {0, 1}, {-1, 0}, {0, -1} };
const int MAXN = 2e5 + 50;
const int Mod = 1e9 + 7;
int n, a, b, root, res, dp[MAXN][5];
vector<vector<int>> tree;
void dim( int node, int fa ){
dp[node][1] = dp[node][2] = 0;
for( int v : tree[node] ){
if( v == fa ) continue;
dim(v, node);
int w = dp[v][1] + 1;
if( w > dp[node][1] ){
dp[node][2] = dp[node][1];
dp[node][1] = w;
}else if( w > dp[node][2] ){
dp[node][2] = w;
}
}
res = max( res, dp[node][1] + dp[node][2] );
}
signed main(){
opt;
cin >> n;
tree.resize(n+5);
for( int i = 1 ; i < n ; i++ ){
cin >> a >> b;
tree[a].pb(b);
tree[b].pb(a);
}
dim(1, 0);
cout << res << "\n";
}
```
## **2. Tree DFS 解題想法**
首先從任一節點 $u$ 開始進行第一次 DFS,到達距離其最遠的節點,並將他記為 $v$,然後再從 $v$ 開始做第二次 DFS,到達距離 $v$ 最遠的節點,記為 $v'$,則 $\delta(z,z')$ 即為樹的直徑。
顯然,如果第一次 DFS 到達的節點 $v$ 是直徑的一端,那麼第二次 DFS 到達的節點 $v'$ 一定是直徑的一端。我們只需證明在任意情況下,$v$ 必為直徑的一端。
定理:在一棵樹上,從任意節點 $u$ 開始進行一次 DFS,到達的距離其最遠的節點 $v$ 必為直徑的一端。
## **2. Tree DFS 完整程式**
```cpp=
/* Question : CSES 1131. Tree Diameter */
/***** 1. DFS Solution *****/
#include<bits/stdc++.h>
using namespace std;
#define opt ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define priq(type) priority_queue<type, vector<type>, greater<type>>
#define mem(x, value) memset(x, value, sizeof(x));
#define pii pair<int, int>
#define pdd pair<double, double>
#define pb push_back
#define f first
#define s second
#define int long long
const auto dir = vector< pair<int, int> > { {1, 0}, {0, 1}, {-1, 0}, {0, -1} };
const int MAXN = 2e5 + 50;
const int Mod = 1e9 + 7;
int endPoint, n, a, b, maxDepth;
vector<vector<int>> tree;
void dfs( int u, int fa, int depth ){
if( depth > maxDepth ){
endPoint = u;
maxDepth = depth;
}
for( auto v : tree[u] ){
if( v == fa ) continue;
dfs(v, u, depth+1);
}
return;
}
```