Description
给定一棵树求最小路径覆盖
Solution
我们需要用上这是一棵树的性质。设f[x]表示x为根的子树内的最小路径覆盖且x是一条路径的端点,g[x]表示x为根的子树内最小路径覆盖且x不是一条路径的端点。
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
const int INF=0x3f3f3f3f;
const int N=20005;
const int E=500005;
struct edge {int y,next;} e[E];
int ls[N],edCnt=1;
int f[N],g[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add_edge(int x,int y) {
e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt;
}
void dfs(int now,int fa) {
f[now]=g[now]=INF;
int rec=INF,sum=0,cnt=0;
for (int i=ls[now];i;i=e[i].next) {
if (e[i].y==fa) continue;
dfs(e[i].y,now); cnt++;
sum+=std:: min(f[e[i].y],g[e[i].y]);
rec=std:: min(rec,std:: max(0,f[e[i].y]-g[e[i].y]));
}
f[now]=sum+std:: min(rec,1);
if (cnt<2) return ;
int mn1=INF,mn2=INF;
for (int i=ls[now];i;i=e[i].next) {
if (e[i].y==fa) continue;
int tmp=std:: max(0,f[e[i].y]-g[e[i].y]);
if (tmp<mn1) mn2=mn1,mn1=tmp;
else if (tmp<mn2) mn2=tmp;
}
g[now]=sum+mn1+mn2-1;
}
int main(void) {
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
for (int T=read();T--;) {
edCnt=1; fill(ls,0);
int n=read();
rep(i,2,n) add_edge(read(),read());
dfs(1,0);
printf("%d\n", std:: min(f[1],g[1]));
}
return 0;
}