顺丰科技8.30日第三题树形dp记录

这篇博客介绍了如何解决一道来自Codeforces的树形动态规划问题,内容涉及数据结构和算法。题目要求在给定的树结构中,每次操作包括节点1,使得所有节点的权值变为0,求最小的操作次数。博主给出了Java代码实现,通过深度优先搜索(DFS)策略,维护增加和减少操作的计数,并计算每个节点的最终状态。最终答案为节点1的增加和减少操作次数之和。
摘要由CSDN通过智能技术生成

8月30日做的一道顺丰笔试题,当时一点思路都没有,后来在网上查了才知道是codeforces上的原题,归类是树形dp,下面来介绍一下这道题以及Java的解法

题目:给出一棵树,每个点有权值,每次操作可以对一个联通子集中的点全部加1,或者全部减1,且每次操作必须包含点1,问最少通过多少次操作可以让整棵树每个点的权值变为0

输入输出格式:

输入:

3
1 2
1 3
1 -1 1

第一行表示这棵树包含的全部节点数;接下来n-1行表示ai和bi之间有边;最后一行表示顺序的每个节点对于的起始权值

输出:

3

思路:

因为每次修改都必须经过点1,所以将点1作为树根开始dfs
因为1是根,所以每次修改一个点,该点到根路径上的点全部都会被做相同的修改

add[i]表示i点增加的次数
del[i]表示i点减小的次数
a[i]表示i点的值

显然当前点的add和del肯定大于等于子节点的add和del
因为当前节点在子节点到根的路径上,所以子节点的修改一定也会施加到当前点。
所以先对于所有子节点v:add[x]=max(add[v]),del[x]=max(del[v])
先计算一下结果:a[x]+=add[x],a[x]-=del[x]
如果a[x]不为0,则a[x]还需要修改,如果大于0则del[x]+=a[x],否则add[x]+=(-a[x])

一直搜到根点1,最后的答案为add[1]+del[1]

Java代码(网上都是c++的):

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

import javafx.scene.layout.CornerRadii;

class Main{
    static Map<Integer,List<Integer>> edges;
    static int[] add;
    static int[] del;
    static int[] score;
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        edges=new HashMap<>();
        add=new int[n+1];
        del=new int[n+1];
        score=new int[n+1];
        for(int i=1;i<n;i++){
            int a=sc.nextInt(); int b=sc.nextInt();
            List<Integer> temp1=edges.getOrDefault(a,new ArrayList<>());
            temp1.add(b);
            edges.put(a, temp1);
            List<Integer> temp2=edges.getOrDefault(b,new ArrayList<>());
            temp2.add(a);
            edges.put(b, temp2);
        }
        for(int i=1;i<=n;i++){
            score[i]=sc.nextInt();
        }
        dfs(1,-1);
        System.out.println(add[1]+del[1]);
    }
    private static void dfs(int root,int lastp){
        List<Integer> list=edges.get(root);
        int m1=0,m2=0;
        for(int v:list){
            if(v==lastp)
                continue;
            dfs(v,root);
            add[root]=Math.max(add[root],add[v]);
            del[root]=Math.max(del[root],del[v]);
        }
        int dif=score[root]+(add[root]-del[root]);
        if(dif>0){
            del[root]+=dif;
        }else{
            add[root]-=dif;
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值