题意:给你一棵树,你可以对结点进行染色,当一个结点被染色之后,与它距离不超过k的所有点都会被染色,要求染最少的点,使得整个图都被染色
题解:
树形dp(bfs)
以1为根,先求出按照bfs序排列的结点,然后按逆bfs序递推
状态:dp[u][0]表示从u开始,能染到的最远的点与u的距离,dp[u][1]表示u的子树中,离u最远的未被染的结点与u的距离
初值:dp[u][0]=-inf
转移:dp[u][0]=max(dp[u][0],dp[v][0]-1),dp[u][1]=max(dp[u][1],dp[v][1]+1),v是u的儿子
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define N 1000010
using namespace std;
int n,k,e_num,inf=1<<30,ans;
int nxt[N<<1],to[N<<1],h[N],dp[N][2],q[N];
bool bj[N];
int gi() {
int x=0,o=1; char ch=getchar();
while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
if(ch=='-') o=-1,ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return o*x;
}
void add(int x, int y) {
nxt[++e_num]=h[x],to[e_num]=y,h[x]=e_num;
}
void bfs() {
int hd,ta;
q[hd=ta=1]=1,bj[1]=1;
while(hd<=ta) {
int u=q[hd++];
for(int i=h[u]; i; i=nxt[i]) {
int v=to[i];
if(bj[v]) continue;
q[++ta]=v,bj[v]=1;
}
}
for(int i=ta; i>=1; i--) {
int u=q[i];
bj[u]=0,dp[u][0]=-inf;
for(int i=h[u]; i; i=nxt[i]) {
int v=to[i];
if(bj[v]) continue;
dp[u][0]=max(dp[u][0],dp[v][0]-1);
dp[u][1]=max(dp[u][1],dp[v][1]+1);
}
if(dp[u][0]>=dp[u][1]) dp[u][1]=-inf;
if(dp[u][1]==k) dp[u][0]=k,dp[u][1]=-inf,ans++;
}
if(dp[1][1]!=-inf) ans++;
}
int main() {
n=gi(),k=gi();
for(int i=1; i<n; i++) {
int x=gi(),y=gi();
add(x,y),add(y,x);
}
bfs();
printf("%d", ans);
return 0;
}