题意:中文题意。
思路:分析完后题意后,攻击先后顺序就是一个有向边,每条边权值1,这个城堡能直接攻击就把他和0点相连。那么这就是一个在树上分组背包的题目。
设:dp[i][j]表示在i点已经攻击了j个城堡的最大值。 dp[i][j]=max(dp[i][j-k]+dp[v][k]); v是i的子节点。
注意多了一个0点后,相当于多了一个城堡。
#include<bits/stdc++.h>
using namespace std;
template<int N,int M>//N点的个数,M边的个数
struct Graph{
int top;
struct Vertex{
int head;
}V[N];
struct Edge{
int v,next;
}E[M];
void init(){
memset(V,-1,sizeof(V));
top = 0;
}
void add_edge(int u,int v){
E[top].v = v;
E[top].next = V[u].head;
V[u].head = top++;
}
};
const int maxn=200+10;
Graph<maxn,maxn*2> g;
int n,m,dp[maxn][maxn],val[maxn],vis[maxn];
void dfs(int u){
dp[u][1]=val[u];
for(int i=g.V[u].head;i!=-1;i=g.E[i].next){
int v=g.E[i].v;
dfs(v);
for(int j=m+1;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){
g.init();
val[0]=0;
for(int i=1;i<=n;i++){
int a,b;scanf("%d%d",&a,&val[i]);
g.add_edge(a,i);
}
memset(dp,0,sizeof(dp));
dfs(0);
printf("%d\n",dp[0][m+1]);
}
}