洛谷 P2279 树形dp

题目链接

题目大意:给定一棵树,设一个关键节点可以覆盖半径为2的范围,问要覆盖整棵树要至少几个关键节点。

这道题可以用贪心或者树形dp解决。因为最近我深感自己dp能力太弱,所有练练dp。

状态设计:

f[p,0]代表将p的祖父覆盖需要的最少关键点数量

f[p,1]代表将p的父亲覆盖需要的最少数量

f[p,2]代表将p覆盖需要的最少数量

f[p,3]代表将p的儿子覆盖需要的最少数量

f[p,4]代表将p的孙子覆盖需要的最少数量

显而易见,f[p,0]≥f[p,1]≥f[p,2]≥f[p,3]≥f[p,4]

状态转移:

设s为p的一个儿子节点。

$$fleft[ p,0 ight] =sum ^{son}_{s}fleft[ s,4 ight]$$

$$fleft[ p,1 ight] =min left( min left{ fleft[ s,0 ight] +sum ^{son}_{j eq s}fleft[ j,3 ight] ight} ,fleft[ p,0 ight] ight)$$

$$fleft[ p,2 ight] =min left( min left{ fleft[ s,1 ight] +sum ^{son}_{j eq s}fleft[ j,2 ight] ight} ,fleft[ p,1 ight] ight)$$

$$fleft[ p,3 ight] =min left( sum ^{son}_{s}fleft[ s,2 ight] ,fleft[ p,2 ight] ight)$$

$$fleft[ p,4 ight] =min left( sum ^{son}_{s}fleft[ s,3 ight] ,fleft[ p,3 ight] ight)$$

那么最终答案就是f[1,2]了。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <utility>
#include <queue>
#include <vector>
#include <list>
#include <set>
#include <map>
#define MAXN 1010
using namespace std;
int n,head[MAXN],to[MAXN*2],nxt[MAXN*2],tot=0,f[MAXN][5];

void connect(int u,int v)
{
    to[++tot]=v;nxt[tot]=head[u];head[u]=tot;
}

void dfs(int u)
{
    f[u][0]=1;f[u][3]=0;f[u][4]=0;
    for(int i=head[u];i;i=nxt[i])
    {
        int v=to[i];
        dfs(v);
        f[u][0]+=f[v][4];
        f[u][3]+=f[v][2];
        f[u][4]+=f[v][3];
    }
    if(head[u]==0)
    {
        f[u][1]=f[u][2]=1;
        return;
    }
    for(int i=head[u];i;i=nxt[i])
    {
        int s=to[i];
        int f1=f[s][0],f2=f[s][1]; 
        for(int j=head[u];j;j=nxt[j])
        {
            if(j==i) continue;
            f1+=f[to[j]][3];
            f2+=f[to[j]][2];
        }
        f[u][1]=min(f[u][1],f1);
        f[u][2]=min(f[u][2],f2);
    }
    for(int i=1;i<=4;i++) f[u][i]=min(f[u][i],f[u][i-1]);
}

int main()
{
    memset(f,0x3f,sizeof(f));
    scanf("%d",&n);
    for(int i=2,v;i<=n;i++)
    {
        scanf("%d",&v);
        connect(v,i);
    }
    dfs(1);
    printf("%d
",f[1][2]);
    return 0;
}
原文地址:https://www.cnblogs.com/BakaCirno/p/11527336.html