昨天和同学叠做题数,做到这题挂了...
同学做法是以 0 为虚根,使 fi,j 表示在 i 节点,取 j 个点的最大值。
而我是跑以父亲为 0 的点为根的若干棵子树,求出 gi,j 表示第 i 棵树上选 j 个点的最大值,最后 01 背包求全局最大值。
另外,如果只把主函数改成
......
dfs(0);
printf("%d",f[0][m+1]);
这道题就过了(即同学和大部分题解做法
#include <bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x)
{
x = 0;
register char c = getchar();
register short f = 1;
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
{
x = (x << 1) + (x << 3) + (c ^ 48);
c = getchar();
}
x *= f;
}
template <typename T, typename... Args>
inline void read(T &x, Args &...temps)
{
read(x), read(temps...);
}
const int N = 305;
int n, m, s[N];
vector<int> G[N];
bool deg[N];
int f[N][N], cnt;
int siz[N];
int g[N][N];
int dp[N];
void dfs(int x)
{
f[x][1] = s[x];
siz[x] = 1;
for (auto y : G[x])
{
dfs(y);
siz[x] += siz[y];
for (int i = siz[x]; i; i--)
for (int j = i - 1; j; j--)
f[x][i] = max(f[x][i], f[x][i - j] + f[y][j]);
}
}
signed main()
{
read(n, m);
for (int i = 1, x; i <= n; i++)
read(x, s[i]),
deg[i] |= !!x,
G[x].emplace_back(i);
for (int i = 1; i <= n; i++)
if (!deg[i])
{
cnt++, dfs(i);
for (int j = 1; j <= m;j++)
g[cnt][j] = f[i][j];
}
if (!cnt)
{
if (n == m)
{
int ans = 0;
for (int i = 1; i <= n; i++)
ans += s[i];
printf("%d", ans);
}
else
puts("0");
}
else
{
for (int i = 1; i <= cnt; i++)
for (int j = 0; j <= m; j++)
for (int k = m; k >= j; k--)
dp[k] = max(dp[k], dp[k - j] + g[i][j]);
printf("%d", dp[m]);
}
return 0;
}