3 2 0 1 0 2 0 3 7 4 2 2 0 1 0 4 2 1 7 1 7 6 2 2 0 0
5 13
题意:见上。
思路:
以0结点为根建立一颗树。对于每一个结点维护一个数组。dp[i][j]表示。结点i子树。消灭j个城堡的最大价值。
dp[i][j]=max(dp[i][j],dp[i][k]+dp[son][j-k])。son为i结点的儿子结点。注意细节。
详细见代码:
#include <iostream> #include<stdio.h> #include<string.h> using namespace std; const int maxn=250; struct node { int v; node *next; } edge[maxn],*head[maxn]; int n,m,cnt,dp[maxn][maxn]; int val[maxn]; void adde(int u,int v) { edge[cnt].v=v; edge[cnt].next=head[u]; head[u]=&edge[cnt++]; } int dfs(int u) { int i,j,to,tot=1,tt;//必须要父结点所以为1 node *p; dp[u][1]=val[u];//一个元素时只能是父结点 if(head[u]==NULL) return tot; for(p=head[u];p!=NULL;p=p->next) { to=p->v; tt=dfs(to); for(i=tot;i>=1;i--)//i最小为1因为必须要父结点。必须倒着更新不然会出问题同01背包 for(j=1;j<=tt&&i+j<=m+1;j++)//加上0结点m+1个结点。 dp[u][i+j]=max(dp[u][i+j],dp[u][i]+dp[to][j]); tot+=tt; } return tot; } int main() { int i,a,b; while(scanf("%d%d",&n,&m),n||m) { cnt=0; val[0]=0; memset(head,0,sizeof head); memset(dp,0,sizeof dp); for(i=1;i<=n;i++) { scanf("%d%d",&a,&b); adde(a,i); val[i]=b; } dfs(0); printf("%d\n",dp[0][m+1]); } return 0; }