1. 程式人生 > >bzoj 1907: 樹的路徑覆蓋【貪心+樹形dp】

bzoj 1907: 樹的路徑覆蓋【貪心+樹形dp】

string cpp print names pos else ++ () post

我是在在做網絡流最小路徑覆蓋的時候找到這道題的
然後發現是個貪心+樹形dp
\( f[i] \)表示在\( i \)為根的子樹中最少有幾條鏈,\( v[i] \) 表示在\( i \)為根的子樹中\( i \) 是( 0)否(1)為一條鏈的端點
然後貪心轉移即可(有鏈端點則連起來)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=10005;
int T,n,h[N],cnt,f[N];
bool v[N];
struct qwe
{
    int
ne,to,va; }e[N<<1]; void add(int u,int v) { cnt++; e[cnt].ne=h[u]; e[cnt].to=v; h[u]=cnt; } void dfs(int u,int fa) { int con=0; f[u]=1; for(int i=h[u];i;i=e[i].ne) if(e[i].to!=fa) { dfs(e[i].to,u); f[u]+=f[e[i].to]; if
(!v[e[i].to]) con++; } if(con==1) f[u]--;//減掉本身 else if(con>1) f[u]-=2,v[u]=1;//減掉本身和其中一個端點 } int main() { scanf("%d",&T); while(T--) { memset(h,0,sizeof(h)); memset(e,0,sizeof(e)); memset(f,0,sizeof(f)); memset(v,0
,sizeof(v)); cnt=0; scanf("%d",&n); for(int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); add(u,v); add(v,u); } dfs(1,0); printf("%d\n",f[1]); } return 0; }

bzoj 1907: 樹的路徑覆蓋【貪心+樹形dp】