题目链接
题意 : 给你一棵树,每个点有一个零食 ,某个人从1号根节点出发,每次尽量走最近的点,最后走完回到1号点,问最小的k。
思路:本来想的是二分+check 发现不可做啊,然后看了别人的题解,原来是有规律的,这道题确实和ccpc秦皇岛的蛮像,也是用的树形dp和贪心的结合,假设我们以u为根(u不是根节点的情况),那么对于每个儿子v所要满足 k > = f [ v ] + 2 k>=f[v]+2 k>=f[v]+2
其中k是能走的最大的范围 f[v]是子节点最浅的位置,由于这个题的特殊性,每次遍历完子树,必然会停在某个叶子节点上,然后再从叶子节点转向另外一个子树,那么走的最优的方案必然是遍历完子树的最后的点停留在离u最近的叶子节点上,那么上来就会方便。然后还有个问题,为什么根节点要特判呢,因为最后回到根节点就行了,就不需要多走1步了,那么我们肯定选择走上来最困难的根的节点,也就是 f v fv fv最大的,因为如果 f v fv fv不加1就说明它要加2了,那肯定没有+1优秀。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define debug printf("---\n");
const int N=200010,M=2*N;
int dp[N],h[N],e[M],ne[M],idx,d[N];
void add(int a,int b)
{
   
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int res=0;
void dfs(int u,int fa)
{
   
	if(d[u]==1 && u!=1)
	{
   
		dp[u]=0;
		return ;
	}
	for(int i=h[u];~i;i=ne[i])
	{
   
		int j=e[i];
		if(j==fa)	continue;
		dfs(j,u);
		dp[u]=min(dp[u],dp[j]+1);
	}
}
vector<int>v;
void dfs2(int u,int fa)
{
   
	int maxv=0;
	//if(u==1)
	if(d[u]==1 && u!=1)
	return ;
	for(int i=h[u];~i;i=ne[i])
	{
   
		int j=e[i];
		if(j==fa)	continue;
		if(u==1)
		{
   
		v.push_back(dp[j]);
		}
		maxv=max(maxv,dp[j]);
		dfs2(j,u);
	}
	if(u==1)
	{
   
	// cout<<v.size()<<endl; 
	res=max(res,maxv+1);
	sort(v.begin(),v.end());
	for(int i=0;i<(int)v.size()-1;i++)
	res=max(res,v[i]+2);
	}
	else
	res=max(res,maxv+2);
}
int main()
{
   
	ios::sync_with_stdio();
	cin.tie(0);
	cout.tie(0);
	int t;
	cin>>t;
	while(t--)
	{
   
		v.clear();
		res=0;
		int n;
		cin>>n;
		for(int i=1;i<=n;i++)
		h[i]=-1;
		idx=0;
		for(int i=1;i<=n;i++)
		d[i]=0,dp[i]=0x3f3f3f3f;
		for(int i=0;i<n-1;i++)
		{
   
			int	a,b;
			cin>>a>>b;
			add(a,b);
			add(b,a);
			d[a]++,d[b]++;
		}
		dfs(1,-1);
		dfs2(1,-1); 
		cout<<res<<endl;
	 } 
	 return 0;
}
/* 3 3 1 2 1 3 4 1 2 2 3 3 4 8 1 2 2 3 3 4 1 5 5 6 6 7 5 8 */