参考博客:https://blog.csdn.net/whzzt/article/details/79321484
核心思想大概是对于一个点u,他所有的连接的点所在的连通块中最多有一个连通块中没有选择的点。
如果有2个以上的话,那么其他连通块通过u点到达那两个连通块上的点dis会出现一样的。
补充一蛤,为什么是O(n)呢,因为从叶子节点找到第一个度>=3的点,中间经过的点必定是一条链,而这条链上的点只经过一次,所以所有叶子节点dfs找到一个度>=3的点,这中间的路径上的点不会重复,所以为O(n),就算整棵树都是链也就是2*n
此题也可以树形DP做,不过直接利用这个结论更方便
#include<bits/stdc++.h>
#define maxl 100010
using namespace std;
int n,ans,cnt;
int ehead[maxl];
int du[maxl];
struct ed
{
int to,nxt;
}e[maxl<<1];
bool vis[maxl];
inline void add(int u,int v)
{
e[++cnt].to=v;e[cnt].nxt=ehead[u];ehead[u]=cnt;
}
inline void prework()
{
for(int i=1;i<=n;i++)
vis[i]=false,ehead[i]=0,du[i]=0;
int u,v;
cnt=0;
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
u++;v++;
add(u,v);du[v]++;
add(v,u);du[u]++;
}
}
inline int dfs(int u,int fa)
{
int v;
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(v==fa) continue;
if(du[v]>2)
return v;
else
return dfs(v,u);
}
}
inline void mainwork()
{
bool flag=true;
for(int i=1;i<=n;i++)
if(du[i]>2)
flag=false;
if(flag)
{
ans=1;
return;
}
ans=0;
for(int i=1;i<=n;i++)
if(du[i]==1)
vis[dfs(i,0)]=true,ans++;
for(int i=1;i<=n;i++)
if(vis[i])
ans--;
}
inline void print()
{
printf("%d\n",ans);
}
int main()
{
while(~scanf("%d",&n))
{
prework();
mainwork();
print();
}
return 0;
}