@ZCDHJ
2019-08-09T03:08:12.000000Z
字数 1240
阅读 514
未分类
的子树中所有点对 的父亲的贡献在颜色相同时是 ,颜色不相同时是 , 是 的子树和。发现只要所有子树的贡献不超过 , 结点可以随便填一个数来满足限制。那么贪心的想就是要所有子树能够造成的贡献最小也就是 最小。因为一棵子树内所有点的相对颜色已经确定,再怎么翻转也不影响本来的答案,所以两种情况可以直接枚举,做一遍 DP 将所有的贡献可能算出来,取一个最大且不超过 的即是最优的决策,此时 最小。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
const int MAXN = 1000;
int n, edge;
int X[MAXN | 1], fst[MAXN | 1];
int sum[MAXN | 1], dp[MAXN | 1][5001];
struct Edge {
int to, nxt;
Edge() : to(0), nxt(0) {}
Edge(int a, int b) : to(b), nxt(fst[a]) {}
} e[MAXN];
inline int read() {
register int x = 0;
register char ch = getchar();
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) {
x = x * 10 + ch - '0';
ch = getchar();
}
return x;
}
inline void addEdge(int a, int b) {
e[++edge] = Edge(a, b);
fst[a] = edge;
}
void DP(int x) {
int size = 0;
for (int k = fst[x]; k; k = e[k].nxt) {
int to = e[k].to;
DP(to);
sum[x] += sum[to];
++size;
}
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for (int i = 1, k = fst[x]; k; k = e[k].nxt, ++i) {
int to = e[k].to;
for (int j = 0; j <= X[x]; ++j) {
if (j >= X[to]) dp[i][j] |= dp[i - 1][j - X[to]];
if (j >= sum[to] - X[to]) dp[i][j] |= dp[i - 1][j - sum[to] + X[to]];
}
}
bool flag = false;
for (int i = X[x]; i >= 0; --i) {
if (dp[size][i]) {
flag = true;
sum[x] += X[x] - i;
break;
}
}
if (!flag) {
puts("IMPOSSIBLE");
exit(0);
}
}
int main() {
n = read();
for (int i = 2; i <= n; ++i) addEdge(read(), i);
for (int i = 1; i <= n; ++i) X[i] = read();
DP(1);
puts("POSSIBLE");
return 0;
}