[10.5模拟] coffee

题意:给你一棵树,你可以对结点进行染色,当一个结点被染色之后,与它距离不超过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;
}

原文地址:https://www.cnblogs.com/HLXZZ/p/7632541.html