送快递(贪心+树形结构)
题意
给一棵\(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;
}