算法训练 结点选择

算法训练 结点选择

@蓝桥杯 算法训练 ALGO-4

问题描述
有一棵 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的正整数。

源码:

import java.io.*;
import java.util.ArrayList;
import java.util.StringTokenizer;

public class Main {

    public static void main(String[] args) throws IOException {
        InputReader read = new InputReader(System.in, " ");
        int n = read.nextInt();
        int [][] dp = new int[2][n + 1];
        ArrayList<Integer>[] graph = new ArrayList[n + 1];
        for (int i = 1; i <= n; i++) {
            dp[1][i] = read.nextInt();
            graph[i] = new ArrayList();
        }
        for (int i = 1, V, E; i < n; i++) {
            V = read.nextInt(); E = read.nextInt();
            graph[V].add(E);
            graph[E].add(V);
        }
        read.close();
        System.out.print(toWeight(graph, dp, dfs(graph, n, 1)));
    }

    static int[] dfs(ArrayList<Integer>[] graph, int size, int E) {
        boolean[] marked = new boolean[size + 1];
        int[] path = new int[size--];
        path[size] = E;
        marked[E] = true;
        for (int l = size; l >=0; l--)
            for (int i :graph[path[l]])
                if (!marked[i]) marked[(path[--size] = i)] = true;
        return path;
    }

    static int toWeight(ArrayList<Integer>[] graph, int[][] dp, int[] path) {
        for (int E: path)
            for (int V: graph[E]) {
                dp[1][V] += dp[0][E];
                dp[0][V] += Math.max(dp[0][E], dp[1][E]);
            }
        return Math.max(dp[0][1], dp[1][1]);
    }

    static class InputReader {

        BufferedReader read;
        StringTokenizer tokens;
        String delimiters;

        InputReader (InputStream in, String delimiters) {
            this.read = new BufferedReader(new InputStreamReader(in));
            this.delimiters = delimiters;
            this.tokens = new StringTokenizer("", delimiters);
        }

        InputReader (InputStream in) { this(in, " \t\n\r\f"); }

        String next() throws IOException {
            while (!tokens.hasMoreTokens()) tokens = new StringTokenizer(read.readLine(), delimiters);
            return tokens.nextToken();
        }

        int nextInt() throws IOException { return Integer.parseInt(next()); }

        void close() throws IOException { read.close(); }
    }
}

下面是改进前的历程

邻接表

用邻接表来描述每个点的所有边,用二维数组存储邻接表。

没有特殊的说明,所以即使题目指明是棵树,但这也是个图问题。树也是图
回溯开始动态规划,计算子图顶点选出与否往下能带来的最大权值。
没有能力讲的很深,见谅

最后只跑了50分,因为超时。

源码:

import java.util.Scanner;

public class Main {
    static int n;
    static int[][] dp;
    static int[][] graph;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        dp = new int[n + 1][2];
        graph = new int[n + 1][4];
        for (int i = 1; i <= n; i++)
            dp[i][1] = sc.nextInt();
        for (int i = 1; i < n; i++) {
            int V = sc.nextInt(), E = sc.nextInt();
            if (++graph[V][0] == graph[V].length) graph[V] = reSize(graph[V], graph[V].length);
                graph[V][graph[V][0]] = E;
            if (++graph[E][0] == graph[E].length) graph[E] = reSize(graph[E], graph[E].length);
                graph[E][graph[E][0]] = V;
        }
        Lost(1, 0);
        System.out.println(Math.max(dp[1][0], dp[1][1]));
    }
    static int[] reSize(int[] former,int size) {
        int[] temp = new int[size * 2];
        System.arraycopy(former, 0, temp, 0, size);
        return temp;
    }
    static void Lost(int E, int V) {
        for (int i = 1; i <= graph[E][0]; i++) {
            int temp = graph[E][i];
            if (temp != V) {
                Lost(temp, E);
                dp[E][1] += dp[temp][0];
                dp[E][0] += Math.max(dp[temp][0], dp[temp][1]);
            }
        }
    }
}

在这里插入图片描述
不过一段时间过后它就能跑70分了
因为蓝桥系统给出的数据终于像个人了

import java.util.ArrayList;
import java.util.Scanner;

public class Main {

    static int [][] dp;
    static ArrayList<Integer>[] graph;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        dp = new int[2][n + 1];
        graph = new ArrayList[n + 1];
        for (int i = 1; i <= n; i++) {
            dp[1][i] = sc.nextInt();
            graph[i] = new ArrayList();
        }
        for (int i = 1, V, E; i < n; i++) {
            V = sc.nextInt(); E = sc.nextInt();
            graph[V].add(E);
            graph[E].add(V);
        }
        dfs(1, 0);
        System.out.print(Math.max(dp[0][1], dp[1][1]));
    }

    static void dfs(int E, int V) {
        for (int i: graph[E])
            if (i != V) {
                dfs(i, E);
                dp[1][E] += dp[0][i];
                dp[0][E] += Math.max(dp[0][i], dp[1][i]);
            }
    }
}

突然有一天在简单了解 BufferedReader 和 Scanner 直接的区别后
封装了一个 BufferedReader 进行对比,需要 nextDouble 之类的方法可以自行封装

static class InputReader {

        BufferedReader read;
        StringTokenizer tokens;
        String delimiters;

        InputReader (InputStream in, String delimiters) {
            this.read = new BufferedReader(new InputStreamReader(in));
            this.delimiters = delimiters;
            this.tokens = new StringTokenizer("", delimiters);
        }

        InputReader (InputStream in) { this(in, " \t\n\r\f"); }

        String next() throws IOException {
            while (!tokens.hasMoreTokens()) tokens = new StringTokenizer(read.readLine(), delimiters);
            return tokens.nextToken();
        }

        int nextInt() throws IOException { return Integer.parseInt(next()); }

        void close() throws IOException { read.close(); }
    }

使用方法:

InputReader read = new InputReader(System.in, " ");
read.nextInt();

在这里插入图片描述
可以看到虽然性能有显著提升,但还是未能满足资源限制,并且出现了运行错误的情况
使用测试用例

InputReader read = new InputReader(new FileInputStream("C:\\Users\\admin\\Downloads\\input8.txt"), " ");

出现了 java.lang.StackOverflowError 栈溢出 错误
递归计划暴死,等会研究出能跑满的方法再发出来






It’s time to let go?

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值