题目链接:http://hihocoder.com/problemset/problem/1050
两种方法:
1. 两遍dfs,第一次随便找一个根,找到距离这个根最远的点,这个点必然是最长链的一端。第二次就用这个端点做一遍dfs,最远的点就是另一端。
#include<bits/stdc++.h> using namespace std; const int maxn=100005; int d[maxn]; vector<int> G[maxn]; void dfs(int u,int fa,int now) { d[u]=now; for (int i=0;i<G[u].size();i++) { int v=G[u][i]; if (v!=fa) dfs(v,u,now+1); } } int main() { int n; scanf("%d",&n); for (int i=0;i<n-1;i++) { int u,v; scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); } dfs(1,0,0); int ma=0,maj=1; for (int i=1;i<=n;i++) { if (d[i]>ma) { ma=d[i]; maj=i; } } dfs(maj,0,0); int ans=0; for (int i=1;i<=n;i++) ans=max(ans,d[i]); printf("%d",ans); return 0; }
2. 树形dp。记dp[i][0/1]表示以i为lca的最长链和次长链的长度,一遍dfs更新就好了。
#include<bits/stdc++.h> using namespace std; const int maxn=100005; int dp[maxn][2]; vector<int> G[maxn]; void dfs(int u,int fa) { for (int i=0;i<G[u].size();i++) { int v=G[u][i]; if (v!=fa) dfs(v,u); } if (G[u].size()<=2) { for (int i=0;i<G[u].size();i++) { int v=G[u][i]; if (v!=fa) dp[u][0]=dp[v][0]+1; } } else { for (int i=0;i<G[u].size();i++) { int v=G[u][i]; if (v!=fa) { if (dp[v][0]+1>dp[u][0]) { dp[u][1]=dp[u][0]; dp[u][0]=dp[v][0]+1; } else dp[u][1]=max(dp[v][0]+1,dp[u][1]); } } } } int main() { int n; scanf("%d",&n); G[1].push_back(0); for (int i=0;i<n-1;i++) { int u,v; scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); } dfs(1,0); int ans=0; for (int i=1;i<=n;i++) ans=max(ans,dp[i][0]+dp[i][1]); printf("%d",ans); return 0; }