树形dp笔记:class1

类1:最小边覆盖问题

题意

在一棵树上选择最少的点使得不被选择的点每个点至少连一条边

思路

状态dp[u][]表示u这个节点不放或放士兵

i:如果当前节点不放置士兵,那么它的子节点必须全部放置士兵

dp[u][0]+=dp[v][1]

ii:如果当前节点放置士兵,它的子节点选不选都可

dp[u][1]+=min(dp[v][0],dp[v][1])

代码

void dfs(int u) {
    vis[u]=1;
    for(int i=0;i<ve[u].size();i++){
        int v=ve[u][i];
        if(!vis[v]){
            dfs(v);
            dp[u][0]+=dp[v][1];
            dp[u][1]+=min(dp[v][0],dp[v][1]);
        }
    }
}

类2:最小点覆盖问题

题意

Farmer John 想让他的所有牛用上手机以便相互交流。他需要建立几座信号塔在 N 块草地中。已知与信号塔相邻的草地能收到信号。给你N−1 个草地(A,B) 的相邻关系,问:最少需要建多少个信号塔能实现所有草地都有信号。

思路

如果选自己,那么是子节点min+1
dp[i][0]+=min(dp[v][0],dp[v][1],dp[v][2])被自己覆盖(预设为1)

如果选儿子,那么有任意一个儿子即可,值为最小子节点(选)+其他(不选)

dp[i][1]=tmp+sum(f[v][0],f[v][1])被自己儿子覆盖

如果选父亲,那么是子节点

dp[i][2]+=min(dp[v][0],dp[v][1])被父亲覆盖

代码

void dfs(int u) {
    vis[u]=1;
    dp[u][0]=1;
    int tmp=0x3f3f3f3f,fl=0;
    for(int i=0;i<ve[u].size();i++){
        int v=ve[u][i];
        if(!vis[v]){
            dfs(v);
            dp[u][0]+=min(dp[v][1],min(dp[v][2],dp[v][0]));
            dp[u][2]+=min(dp[v][0],dp[v][1]);
            /*if(ve[v].size()==0){
                dp[u][1]=0x3f3f3f3f;
                return;
            }*/
            /*else{*/
                dp[u][1]+=min(dp[v][0],dp[v][1]);
                tmp=min(tmp,dp[v][0]-dp[v][1]);
            /*}*/
        }
    }
    if(tmp>=0){
        dp[u][1]+=tmp;
    }
}

类3:背包

题意

有一棵二叉苹果树,如果数字有分叉,一定是分两叉,即没有只有一个儿子的节点。这棵树共N个节点,标号1至N,树根编号一定为1。
我们用一根树枝两端连接的节点编号描述一根树枝的位置。一棵有四根树枝的苹果树,因为树枝太多了,需要剪枝。但是一些树枝上长有苹果,给定需要保留的树枝数量,求最多能留住多少苹果。

思路

与01背包类似,外层枚举总容量,内层枚举子树中选择留下的个数,dp[u][k]=min(dp[u][k-j]+dp[v][j-1]+w)

代码

void dfs(int u) {
    vis[u]=1;
    //dp[][]=;
    for(int i=0;i<ve[u].size();i++){
        int v=ve[u][i].first,w=ve[u][i].second;
        //cout<<u<<' '<<v<<' '<<w<<endl;
        if(!vis[v]){
            dfs(v);
            for(int k=q;k>=1;k--){
                for(int j=1;j<=k;j++){
                    //cout<<dp[u][k]<<' '<<dp[u][k-j]<<' '<<dp[v][j-1]<<' '<<w<<endl;
                    if(dp[u][k]<dp[u][k-j]+dp[v][j-1]+w)
                        dp[u][k]=dp[u][k-j]+dp[v][j-1]+w;
                }
            }
        }
    }
}

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值