http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1378
题意:
思路:
要想放得少,尽量放在叶子节点处,叶子节点处点比较多。
从叶子节点开始往上回溯,到第k个点时就放置一名家丁,用dp[x]来记录状态,若为负,则表示该节点及其子树所需要家丁的最远距离,若为正,则表示该节点及其子树中家丁还能镇压的最大距离。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int maxn = 100000+5; 6 const int inf = 0x3f3f3f3f; 7 8 int n,k,tot,ans; 9 int head[maxn],dp[maxn]; 10 11 struct node 12 { 13 int v,next; 14 }e[2*maxn]; 15 16 void addEdge(int u, int v) 17 { 18 e[tot].v = v; 19 e[tot].next = head[u]; 20 head[u] = tot++; 21 } 22 23 void dfs(int u, int fa) 24 { 25 int mi = inf; 26 int mx = -inf; 27 for(int i=head[u];i!=-1;i=e[i].next) 28 { 29 int v = e[i].v; 30 if(v == fa) continue; 31 dfs(v,u); 32 mx = max(mx,dp[v]); 33 mi = min(mi,dp[v]); 34 } 35 if(mi == inf) //叶子节点的情况 36 { 37 dp[u] = -1; 38 } 39 else if(mi <= -k) //有节点超过k距离了,此时u必须要放置家丁 40 { 41 ans++; 42 dp[u] = k; 43 } 44 else if(mx+mi > 0) //有节点能镇压住家丁 45 { 46 dp[u] = mx - 1; 47 } 48 else //向上请求家丁 49 dp[u] = mi - 1; 50 } 51 52 int main() 53 { 54 //freopen("in.txt","r",stdin); 55 scanf("%d%d",&n,&k); 56 tot = ans = 0; 57 memset(head,-1,sizeof(head)); 58 for(int i=1;i<n;i++) 59 { 60 int u,v; 61 scanf("%d%d",&u,&v); 62 addEdge(u,v); 63 addEdge(v,u); 64 } 65 if(k==0) {printf("%d\n",n);return 0;} 66 dfs(0,-1); 67 if(dp[0]<0) ans++; 68 printf("%d\n",ans); 69 return 0; 70 }