说在前面
并没有什么想说的,但是要保持格式=w=
题目
题目大意
给出一棵
n
n
个节点的树,求该树的最小支配集
一个点可以支配与它相临的点
支配集:选出一个集合,满足所有点都被支配
范围:
输入输出格式
输入格式:
一棵树的常识输入
输出格式:
输出一个整数表示答案
解法
树形dp是可以的,而且很显然
要不是有这个贪心me也不会写这一篇
注意到,如果我们把子树内的选择方案确定了,那么向上的最优方案是可以构造的
因为我们要尽可能多的覆盖点,假设子树已经被覆盖,那么当 儿子/自己/父亲 都没有被选择的时候,选择父亲,这样就能尽可能多的覆盖住所有点
那么边界情况是什么呢?因为要覆盖住叶子节点,所以要么选叶子,要么选叶子的父亲。显然选择父亲节点要更优一些
所以就可以直接贪心构造
下面是代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
int N , tp , head[10005] , chose[10005] , ans ;
struct Path{
int pre , to ;
}p[20005] ;
void In( int t1 , int t2 ){
p[++tp] = ( Path ){ head[t1] , t2 } ; head[t1] = tp ;
p[++tp] = ( Path ){ head[t2] , t1 } ; head[t2] = tp ;
}
void dfs( int u , int f ){
bool son = false ;
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
if( v == f ) continue ;
dfs( v , u ) ; son |= chose[v] ;
} if( !son && !chose[u] && !chose[f] )
chose[f] = true , ans ++ ;
}
void solve(){
dfs( 1 , 1 ) ;
printf( "%d" , ans ) ;
}
int main(){
scanf( "%d" , &N ) ;
for( int i = 1 , u , v ; i < N ; i ++ ){
scanf( "%d%d" , &u , &v ) ;
In( u , v ) ;
} solve() ;
}