洛谷OJ:P3698 [CQOI2017]小Q的棋盘

题目描述

小 Q 正在设计一种棋类游戏。

在小 Q 设计的游戏中,棋子可以放在棋盘上的格点中。某些格点之间有连线,棋子只能在有连线的格点之间移动。整个棋盘上共有 V 个格点,编号为0,1,2 … , V− 1,它们是连通的,也就是说棋子从任意格点出发,总能到达所有的格点。小 Q 在设计棋盘时,还保证棋子从一个格点移动到另外任一格点的路径是唯一的。

小 Q 现在想知道,当棋子从格点 0 出发,移动 N 步最多能经过多少格点。格点可以重复经过多次,但不重复计数。

输入格式

第一行包含2个正整数V, N,其中 V 表示格点总数,N 表示移动步数。

接下来V − 1行,每行两个数a_i,b_iai​,bi​,表示编号为a_i,b_iai​,bi​的两个格点之间有连线。

输出格式

输出一行一个整数,表示最多经过的格点数量。

洛谷OJ:P3698 [CQOI2017]小Q的棋盘_第1张图片

说明/提示

【输入输出样例 1 说明】

从格点 0 出发移动 2 步。经过 0, 1, 2 这 3 个格点。

【输入输出样例 2 说明】

一种可行的移动路径为 0 → 1 → 3 → 5 → 3 → 7,经过 0, 1, 3, 5, 7 这 5 个格点。

【数据规模与约定】

对于 100%的测试点,N,V ≤ 100, 0 ≤a_i,b_i< V

思路:先考虑直接直接按最长链走,如果走完最长链有多的步数,可以在开始先走支链,贡献按2步/一个节点算。这样必然是最优的。

class Solution {

    private static int[] depth;
    private static boolean[] used;
    private static List> edges;

    public static void main(String[] args) {

        int n, m, u, v, ans = 0;
        Scanner in = new Scanner(System.in);

        n = in.nextInt();
        m = in.nextInt();
        depth = new int[n];
        used = new boolean[n];
        edges = new ArrayList<>();

        for (int i = 0; i < n; i++)
            edges.add(new ArrayList<>());

        for (int i = 1; i < n; i++) {
            u = in.nextInt();
            v = in.nextInt();
            edges.get(u).add(v);
            edges.get(v).add(u);
        }

        dfs(0);

        for (int i = 0; i < n; i++)
            ans = Math.max(ans, depth[i] + 1);

        if (m <= ans - 1)
            System.out.println(m + 1);
        else
            System.out.println(Math.min(n, ans + (m - ans + 1) / 2));

    }

    private static void dfs(int u) {

        used[u] = true;
        for (int i = 0; i < edges.get(u).size(); i++) {
            int v = edges.get(u).get(i);
            if (used[v]) continue;
            depth[v] = depth[u] + 1;
            dfs(v);
        }

    }
}

 

你可能感兴趣的:(洛谷OJ:P3698 [CQOI2017]小Q的棋盘)