【思特奇杯·云上蓝桥-算法集训营】第3周 节点选择

节点选择

问题描述

有一棵 n 个节点的树,树上每个节点都有一个正整数权值。如果一个点被选择了,那么在树上和它相邻的点都不能被选择。求选出的点的权值和最大是多少?

输入格式

第一行包含一个整数 n 。

接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值。

接下来一共 n-1 行,每行描述树上的一条边。

输出格式

输出一个整数,代表选出的点的权值和的最大值。

样例输入

5
1 2 3 4 5
1 2
1 3
2 4
2 5

样例输出

12

样例说明

选择3、4、5号点,权值和为 3+4+5 = 12 。

数据规模与约定

对于20%的数据, n <= 20。

对于50%的数据, n <= 1000。

对于100%的数据, n <= 100000。

权值均为不超过1000的正整数。


Code

public class code03_choose {
    public static void main(String[] args) {
        new code03_choose().count();
    }

    public Scanner sc;
    public int[][] weight;// 权值  [][0]表示不选择这个节点,[][1]表示选择这个节点
    public List<List<Integer>> adj;// 邻接表

    public void count() {
        weight = new int[100001][2];// 下标从1开始
        sc = new Scanner(new InputStreamReader(System.in));
        while (sc.hasNext()) {
            adj = new ArrayList<List<Integer>>();// 头指针的线性表
            input();
            dfs(1, 0);// 1根节点,0无前驱结点
            System.out.println(Math.max(weight[1][0], weight[1][1]));
        }
        sc.close();
    }

    private void input() {
        int n = sc.nextInt();// 结点数
        adj.add(new ArrayList<Integer>());
        for (int i = 1; i <= n; i++) {
            weight[i][0] = 0;
            weight[i][1] = sc.nextInt();
            adj.add(new ArrayList<Integer>());// 创建头结点
        }
        int head, tail;// 弧的头尾
        for (int i = 1; i < n; i++) {
            tail = sc.nextInt();
            head = sc.nextInt();
            adj.get(tail).add(head);// 添加表结点
            adj.get(head).add(tail);// 无向图,添加表结点
        }
    }

    private void dfs(int root, int pre) {// pre为前驱结点
        List<Integer> list = adj.get(root);// 当前链表
        for (Integer i : list) {
            if (i != pre) {
                dfs(i, root);
                // 不选root点
                weight[root][0] += Math.max(weight[i][0], weight[i][1]);
                // 选root点
                weight[root][1] += weight[i][0];
            }
        }
    }

}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值