送快递(贪心+树形结构)

题意

给一棵\(n\)个点的树,每条边的边权为\(1\)。从\(0\)号点开始走,问走\(k\)步,最多能都多少个不重复的点(包括\(0\)号点)

数据范围

\(2 \leq n \leq 1000\)
\(1 \leq k \leq 3000\)

思路

贪心。可以先考虑最长链,只有最长链走的尽可能长,才会使得结果最优。最长链上的点,每走一步,都会走到一个新点
然后再考虑非最长链上的点,如果要走非最长链上的点,那么就需要从最长链上的点走过去,然后再回到最长链上,相当于路径走了两次,也就是每走两步,会到达一个新点。
那么我们可以先统计最长链上点的个数,与\(k\)比较,然后再看看剩下的步数能走多少点。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010, M = 2 * N;

int n, k;
int h[N], e[M], ne[M], idx;
int dist[N];

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

void dfs(int u, int fa, int dep)
{
    dist[u] = dep;
    for(int i = h[u]; ~i; i = ne[i]) {
        int j = e[i];
        if(j == fa) continue;
        dfs(j, u, dep + 1);
    }
}

int main()
{
    memset(h, -1, sizeof(h));
    scanf("%d%d", &n, &k);
    int cnt = n;
    for(int i = 1; i <= n; i ++) {
        int x;
        scanf("%d", &x);
        add(i, x), add(x, i);
    }
    dfs(0, -1, 0);
    int max_long = 0;
    for(int i = 1; i <= n; i ++) max_long = max(max_long, dist[i]);
    if(k <= max_long) printf("%d\n", k + 1);
    else {
        cnt -= max_long + 1;
        k -= max_long;
        int ans = max_long + 1;
        k /= 2;
        if(k >= cnt) ans += cnt;
        else ans += k;
        printf("%d\n", ans);
    }
    return 0;
}
posted @ 2021-01-26 09:17  pbc的成长之路  阅读(84)  评论(0编辑  收藏  举报