51nod 1378:夹克老爷的愤怒

51nod 1378:夹克老爷的愤怒

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1378

题目大意:给出一颗结点为​$n(1 leqslant n leqslant 100000 )$的树,若每设置一个点使得距离该点不超过$k(0leqslant k leqslant n )$​的结点均被覆盖,问全部覆盖整颗树需要设置的最少的点为多少.

贪心

显然从叶结点开始向根延伸,每到必须放置的时候放置一个点,遍历到根时若根没被覆盖则放置点个数$+1$,这种方法得到的放置点个数最少(考虑若从根开始向叶结点延伸,遍历到叶节点时若叶节点没被覆盖则放置点个数$+M$,$M$为没被覆盖的叶节点数).

具体操作为dfs返回每个点向上未被覆盖的距离$dis(-k leqslant dis leqslant k)$.

对于结点$u$,维护其每个孩子$v$返回$dis$的最大值$maxn$及最小值$minn$,若$maxn leqslant k$,则在结点$u$放置覆盖点.

复杂度为$O(n)$.

代码如下:

 1 #include <cstdio>
 2 #include <vector>
 3 #define N 100005
 4 using namespace std;
 5 int ans,x,y,n,k;
 6 vector<int>e[N];
 7 int dfs(int x,int f){
 8     if(e[x].size()==1&&e[x][0]==f)return 1;
 9     int minn=k+1,maxn=-k-1;
10     for(int i=0;i<(int)e[x].size();++i)if(e[x][i]!=f){
11         int d=dfs(e[x][i],x);
12         maxn=max(maxn,d);
13         minn=min(minn,d);
14     }
15     if(maxn>=k){
16         ans++;
17         return -k;
18     }else return (minn+maxn<0?minn:maxn)+1;
19 }
20 int main(void){
21     scanf("%d%d",&n,&k);
22     for(int i=1;i<n;++i){
23         scanf("%d%d",&x,&y);
24         e[x].push_back(y);
25         e[y].push_back(x);
26     }
27     if(k==0){
28         printf("%d
",n);
29     }else{
30         if(dfs(0,-1)>0)ans++;
31         printf("%d
",ans);
32     }
33 }
原文地址:https://www.cnblogs.com/barrier/p/6734029.html