由依赖关系建图,如果访问v节点必须先访问u节点,则加边(u, v)。由于题意给的是森林,所以添加0节点,点权值为0正好将森林转为有根树。dp[i][j]表示在i节点,还能访问j个节点所能获得的最大值,由于有0节点,所以答案便是dp[0][m+1]。对于边(u, v)状态转移方程:
dp[u][j] = max(dp[u][j], dp[u][j-k] + dp[v][k]); 即在v及其子树访问k个点,剩下的留给u的其他子节点所能获得的最大值。
#include<iostream> #include<algorithm> #include<vector> #include<cstdio> #include<cstring> using namespace std; #define clr(a, b) memset(a, b, sizeof(a)) const int maxn = 222; int dp[maxn][maxn], val[maxn]; int n, m; vector<int> G[maxn]; void dfs(int u, int res) { int nc = G[u].size(); dp[u][1] = val[u]; for(int i=0; i<nc; i++) { int v = G[u][i]; if(res > 1) dfs(v, res - 1); for(int j=res; j>1; j--) for(int k=1; k<j; k++) dp[u][j] = max(dp[u][j], dp[u][j-k] + dp[v][k]); } } int main() { while(~scanf("%d%d", &n, &m), n || m) { clr(dp, 0); clr(val, 0); for(int i=0; i<=n; i++) G[i].clear(); int a; for(int i=1; i<=n; i++) { scanf("%d%d", &a, &val[i]); G[a].push_back(i); } dfs(0, m+1); printf("%d\n", dp[0][m+1]); } return 0; }