P9 CF2050G Tree Destruction
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(){
IOS
int 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

浙公网安备 33010602011771号