树形DP,贪心思想,从叶子节点向上,能不放就不放,到了k长就放一个。
后序遍历,记录不同子树上传的状态,子树状态记录为该子树可以向上管理的(缺少的用负数)
可能A子树放置的家丁可以把B子树的村庄全部覆盖,这样就可以节约家丁数了。
min_length = min(dp[child])
max_length = max(dp[child])
if(min_length <= -K) {
++result;
dp[cur_idx] = K; //子树需要暴力支援深度达到K了,必须在当前位置放置一个家丁,并向上提供K的暴力输出
} else if(max_length + min_length > 0) {
dp[cur_idx] = max_child - 1; //有一个子树放置的家丁能够把全部其他需要镇压的村庄都覆盖
} else {
dp[cur_idx] = min_child - 1; //继续向上级要求暴力支持
}
++result;
dp[cur_idx] = K; //子树需要暴力支援深度达到K了,必须在当前位置放置一个家丁,并向上提供K的暴力输出
} else if(max_length + min_length > 0) {
dp[cur_idx] = max_child - 1; //有一个子树放置的家丁能够把全部其他需要镇压的村庄都覆盖
} else {
dp[cur_idx] = min_child - 1; //继续向上级要求暴力支持
}
最后如果root的状态小于0要额外多放一个。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
const int maxn=1e5+5;
int dp[maxn];
vector<int>v[maxn];
int n,k,x,y,ans=0;
void dfs(int u,int pre)
{
int max1=-maxn,min1=maxn;
for(int i=0; i<v[u].size(); i++)
{
if(v[u][i]==pre)continue;
dfs(v[u][i],u);
max1=max(max1,dp[v[u][i]]);
min1=min(min1,dp[v[u][i]]);
}
if(max1==-maxn)max1=min1=0;
if(max1>=k)ans++,dp[u]=-k;
else if(min1<0&&min1+max1<0)
{
dp[u]=min1+1;
}
else dp[u]=max1+1;
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1; i<n; i++)
{
scanf("%d%d",&x,&y);
v[x].pb(y);
v[y].pb(x);
}
dfs(0,-1);
if(dp[0]>0)ans++;
printf("%d\n",ans);
return 0;
}