zoukankan      html  css  js  c++  java
  • 洛谷 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;
    }
  • 相关阅读:
    Jetpack MVVM 高频提问和解答
    Android-Jetpack架构组件-—-Navigation#
    Jetpack明星组件 —ViewModel #
    Android开发把 LiveData 用于事件传递那些坑#
    Android官方架构组件Lifecycle#
    Android架构组件JetPack之Lifecycle#
    Android架构组件JetPack之LiveData的工作原理#
    DataBinding从入门到通透#
    SpringBoot 分包方式多数据源
    SpringBoot与数据访问
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/11527336.html
Copyright © 2011-2022 走看看