P3698 [CQOI2017] 小Q的棋盘

原题链接:P3698 [CQOI2017] 小Q的棋盘

题目描述

一个节点数为 $n$ 的树,从节点 $0$ 出发走 $m$ 步做多可以走多少个节点(可以经过一个节点多次)。

输入格式

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

接下来 $V-1$ 行,每行两个数 $a_i,b_i$,表示编号为$a_i,b_i$ 的两个格点之间有连线。

输出格式

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

样例 #1

样例输入 #1

5 2
1 0
2 1
3 2
4 3

样例输出 #1

3

样例 #2

样例输入 #2

9 5
0 1
0 2
2 6
4 2
8 1
1 3
3 7
3 5

样例输出 #2

5

提示

【输入输出样例 1 说明】

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

【输入输出样例 2 说明】

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

【数据规模与约定】

对于 $100\%$ 的测试点,$1\le N,V ≤ 100$,$0 ≤a_i,b_i< V$。


题解 1

以一条链为例,每走一步会多经过一个新的点;

当该链全部被遍历时,可以尝试走子节点,此时平均需要花费 $2$ 步来经过一个新的点(去+回);

因此显然是一个贪心问题,只需讨论最长链的长度与 $m$ 的关系即可。

代码 1

#include <bits/stdc++.h>
using namespace std;
const int N = 110;

int n, m;
vector<int> G[N];
int d[N];
int maxd = 1;

void dfs(int u, int fa) {
    for (int v : G[u]) {
        if (v != fa) {
            d[v] = d[u] + 1;
            maxd = max(maxd, d[v]);
            dfs(v, u);
        }
    }
}

int main() {
    cin >> n >> m;
    for (int i = 1;i < n;i++) {
        int u, v; cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    d[0] = 1;
    dfs(0, 0);
    if (maxd >= m) cout << min(m + 1, maxd) << '\n';
    else cout << min(n, maxd + ((m - maxd + 1) >> 1)) << '\n';
    return 0;
}

题解 2

代码 2