Crisis
题目大意
给你一棵树,然后你可以选一些叶子结点。
对于一个点,如果它的儿子有超过 T% 被选,它也会被选。
问要让根节点被选最少要选多少个叶子节点。
思路
不难看出是树形 DP,
f
i
f_i
fi 为
i
i
i 选中要多少个叶子节点。
(我这里写的
f
i
,
0
/
1
f_{i,0/1}
fi,0/1 是
i
i
i 子树解决
i
i
i 不选中或选中的最小花费,但明显
f
i
,
0
=
0
f_{i,0}=0
fi,0=0 所以其实是没必要的)
那对于每个点你可以求出要有多少个儿子选中,然后你就选
f
f
f 值最小的那些,这个你可以拿出来排个序或者直接丢进去一个堆里面。
然后最后输出
f
0
f_0
f0 即可。
代码
#include<queue>
#include<cstdio>
using namespace std;
const int N = 100005;
struct node {
int to, nxt;
}e[N];
int n, t, fa[N], le[N], KK;
int sta[N], stn, f[N][2];
int chu[N];
priority_queue <int, vector<int>, greater<int> > q;
void add(int x, int y) {
e[++KK] = (node){y, le[x]}; le[x] = KK;
}
int main() {
scanf("%d %d", &n, &t);
for (int i = 1; i <= n; i++) {
scanf("%d", &fa[i]);
add(fa[i], i);
chu[fa[i]]++;
}
sta[++stn] = 0;
for (int qq = 1; qq <= stn; qq++) {
int now = sta[qq];
for (int i = le[now]; i; i = e[i].nxt)
sta[++stn] = e[i].to;
}
for (int qq = stn; qq >= 1; qq--) {
int now = sta[qq];
if (!chu[now]) {
f[now][0] = 0; f[now][1] = 1;
continue;
}
f[now][0] = 0;
while (q.size()) q.pop();
for (int i = le[now]; i; i = e[i].nxt) {
q.push(f[e[i].to][1]);
}
int num = 0;
while (num * 100 < chu[now] * t) {
num++;
f[now][1] += q.top();
q.pop();
}
}
printf("%d", f[0][1]);
return 0;
}