1. 程式人生 > >bzoj1907 樹的路徑覆蓋 樹形dp

bzoj1907 樹的路徑覆蓋 樹形dp

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; }