bzoj1907 樹的路徑覆蓋 樹形dp
阿新 • • 發佈:2018-12-23
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;
}