CF Round 991 (div.3) G
十分经典的树形DP,但是我却对此十分畏惧...
这题思路上没什么好说的,很容易就能想到用DP。要说麻烦,主要可能就是理清树上的链和点之间的关系,方便构造转移方程。
对于以 \(pos\) 为根的子树,如果我们要找一条链在此子树中,那本质上就是两个状态:\(pos\) 在链上或者不在。不过对于本题由于只选择一条链,所以可以将 \(pos\) 在链上的情况转化成 \(pos\) 在链端点和不在端点。这样在 DFS 的时候方便转移。
const int N=200010;int n,f[N][3],_out[N];//不在,端点,中间(只需考虑以pos为根的子树)
vector<int> G[N];inline void dfs(int pos,int fafa){f[pos][0]=f[pos][1]=1;int mx1=0,mx2=0;for(int to:G[pos]){if(to==fafa) continue;dfs(to,pos);f[pos][0]=max(f[pos][0],max({f[to][0],f[to][1]+1,f[to][2]+1}));f[pos][1]=max(f[pos][1],f[to][1]);if(f[to][1]>mx1) mx2=mx1,mx1=f[to][1];else if(f[to][1]>mx2) mx2=f[to][1];}f[pos][1]+=_out[pos]-2;if(mx1&&mx2) f[pos][2]=mx1+mx2+_out[pos]-3;
}inline void solve(){memset(f,0,sizeof(f));dfs(1,1);cout<<max({f[1][0],f[1][1]+1,f[1][2]+1})<<'\n';
}signed main(){IOSint T;cin>>T;while(T--){cin>>n;for(int i=1;i<=n;++i)G[i].clear(),_out[i]=0;for(int i=1;i<n;++i){int fo,to;cin>>fo>>to;G[fo].pb(to),G[to].pb(fo);_out[fo]++,_out[to]++;} solve();}return 0;
}
我写的代码中需要注意的是,在状态转移时出入度值的变化,由于 DFS 中不需要考虑父节点,但是回溯时又得考虑。并且根节点不存在父节点,所以我卡了半天......
· EOF