这题主要是树形dp
思路就是01背包,小细节都写在代码里了
#include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> #include <vector> using namespace std; const int maxn = 2e2+5; int n,m; vector<int> tree[maxn]; int dp[maxn][maxn]; bool vis[maxn]; void dfs(int u); int main() { int i,j,k,a,b; while(scanf("%d%d",&n,&m) && (n||m)) { m++; //因为有个0节点 所以一共要考虑m+1个点 0节点的价值为0 memset(dp, 0, sizeof(dp)); for(i=0;i<=n;++i) { tree[i].clear(); } for(i=1;i<=n;++i) { scanf("%d%d",&a,&b); dp[i][0] = 0; dp[i][1] = b; tree[a].push_back(i); } dfs(0); printf("%d ",dp[0][m]); } } void dfs(int u) { int i,j,k; for(i=0;i<tree[u].size();++i) { int t=tree[u][i]; if(tree[t].size()) dfs(t); for(j=m;j>=2;--j) { for(k=1;k<j;++k) { /* 这个地方我当时想了一个问题 1 2 3 4 7 6 8 10 9 11 假设我现在要求dp[3][4] 假设3点价值3 7点价值1 6点价值2 8点价值1 10点价值1 11点价值2 dp[3][4] = max(dp[3][4],dp[3][2]+dp[6][2]); 那么问题来了 dp[3][2]的最大价值是5 dp[6][2]的价值是4 但是6这个点被取了两次,我怎么才能保证6不被取两次呢 其实这个也不难想,画一遍也就明白了 现在到达3节点,7子节点没有儿子,这时候只有3、7节点被考虑了 接下6节点有儿子,进入后,经过一系列操作求出dp[6][1..m] 这时候才3、6、7被考虑到 所以说不存在6被多次取到的情况 */ dp[u][j]=max(dp[u][j],dp[u][k]+dp[t][j-k]); } } } }