题意:
给定一颗树,定义一种结构为芽节点(不是根节点且有子节点而且子节点都是叶子节点),我们可以把芽与芽的父节点断开,然后重新拼接到任意节点后使得叶子节点总数最少。
思路:
因为芽节点可以摘下来,那么我们把所有芽节点先全部拆下来后发现这棵树除了根节点,芽节点就是叶子节点,并且他们无法相互转换,所以我们把树拆成一个个不能分解的芽节点后,答案初始为一个根节点,然后每个芽节点的贡献为其叶子节点数 − 1 -1 −1,统计所有芽节点的贡献就行了。
#include<bits/stdc++.h>
#define maxn 400002
using namespace std;
int n,h[maxn],cnt,u,v,ye[maxn],ya[maxn],vis[maxn],ans,sum[maxn];
struct ona{
int v,next;
}e[maxn];
void add(int u,int v){
e[++cnt].v=v;
e[cnt].next=h[u];
h[u]=cnt;
}
void dfs(int x,int fa){
vis[x]=1;
int f=0;
for(int i=h[x];i;i=e[i].next){
int to=e[i].v;
if(vis[to])continue;
dfs(to,x);
if(ye[to])f=1;
}
if(!f)ye[x]=1;
else ya[x]=1;
if(ya[x]||x==1)
for(int i=h[x];i;i=e[i].next){
int to=e[i].v;
if(to==fa)continue;
if(ye[to])sum[x]++;
}
if(sum[x])ans+=sum[x]-1;
}
void work(){
cnt=0;
ans=1;
scanf("%d",&n);
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs(1,0);
printf("%d\n",ans);
for(int i=1;i<=n*2;i++){
e[i].v=0;
e[i].next=0;
vis[i]=0;
ya[i]=0;
ye[i]=0;
sum[i]=0;
h[i]=0;
}
}
int main(){
int t;
scanf("%d",&t);
while(t--)
work();
return 0;
}