1. 程式人生 > 其它 >[Acwing藍橋杯DP] 1078. 旅遊規劃

[Acwing藍橋杯DP] 1078. 旅遊規劃

題目連結:1078. 旅遊規劃 - AcWing題庫

題目大意:  求一個樹上,直徑上的所有的點

資料範圍:節點n    1<=n<=2e5

範圍很大 要求時間複雜度控制在 lnn 以內

分析:

這是一個樹形DP,基於樹的直徑,求樹所有直徑上的點

整體思路:

1、先通過樹形dp求出每個點往下走的最大長度和次大長度,並且更新整棵樹的最大路徑maxx

2、往下走最大值(第一步已求) + 往上走最大值 == maxx,即在直徑上

這個題的難點就是:

首先要理解為什麼一個節點既要往上求,又要往下求?

因為第一次dfs時候,回溯時候,是從下往上的,先求下面的點,再上邊的

藉助y總畫的圖容易理解

 

 

還有就是理解那三個陣列:d1往下最大值 d2往下的次大值 up是往上的最大值(實際上就是配合p陣列,求最大值)

 

還有就是p陣列的理解: p[u]=j :從u下去是j  。

 

比如一個點 i 往下的最大值和次大值是確定的,往上不確定,往上是遞迴,這裡的往上也不是嚴格意義的往上,是相較與上次遞歸向下而言的,也有可能向下。

 

這個p陣列就是為了防止向下時候最大值算兩邊,如果是最大值就取次小值。反正這個up值是一直取最大的。

 

看程式碼:

 

 

#include <bits/stdc++.h>

using namespace std;

const int N=2e5+10
,M=2*N; int n; int h[N],e[M],ne[M],idx; int d1[N],d2[N],p[N],up[N]; int maxx; void add(int a,int b) { e[idx]=b,ne[idx]=h[a],h[a]=idx++; } void dfs1(int u,int father) { for(int i=h[u];~i;i=ne[i]) { int j=e[i]; if(j!=father) { dfs1(j,u); int
d=d1[j]+1; if(d>d1[u]) { d2[u]=d1[u]; d1[u]=d; p[u]=j; }else if(d>d2[u]) { d2[u]=d; } } } maxx=max(maxx,d1[u]+d2[u]); } void dfs2(int u,int father) { for(int i=h[u];~i;i=ne[i]) { int j=e[i]; if(j!=father) { up[j]=up[u]+1; if(p[u]==j) { up[j]=max(up[j],d2[u]+1); }else { up[j]=max(up[j],d1[u]+1); } dfs2(j,u); } } } int main() { memset(h,-1,sizeof (h)); cin>>n; for(int i=0;i<n;i++) { int a,b; scanf("%d%d",&a,&b); add(a,b); add(b,a); } dfs1(0,-1); dfs2(0,-1); for(int i=0;i<n;i++) { int a[3]={d1[i],d2[i],up[i]}; sort(a,a+3); if(a[2]+a[1]==maxx) { cout<<i<<endl; } } return 0; }

 

 

 

 

END!!!