ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得里面的宝物。但由于地理位置原因,有些城堡不能直接攻克,要攻克这些城堡必须先攻克其他某一个特定的城堡。你能帮ACboy算出要获得尽量多的宝物应该攻克哪M个城堡吗?
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中文题,题意就很明白了,很明显的树形dp,其实还是搞不清楚树形dp具体应该怎么写,暂时就是看感觉吧。跟普通的dp一样,首先要找状态转移方程。
dp[i][j]表示当前i节点及其子树下选择j个城市的最大值为dp[i][j]。则状态转移方程为:dp[fa][j] = max(dp[fa][j] , dp[fa][k] + dp[son][j-k]);
借用大佬学弟的话说:树形dp就是dp和dfs的结合,一直无法理解,暂时还是只能写简单的树形dp吧
#include<iostream>
#include<stdio.h>
#include<string>
#include<math.h>
#include<queue>
#include<vector>
#include<string.h>
#include<iterator>
using namespace std;
vector<int>tree[205];
int n , m;
int dp[205][205] ;
void dfs(int fa){
for(int i = 0 ; i < tree[fa].size() ; i ++){
int son = tree[fa][i] ;
if(tree[son].size() > 0)
dfs(son);
for(int j = m ; j > 1 ; j --){
for(int k = 1 ; k < j ; k ++){
dp[fa][j] = max(dp[fa][j] , dp[fa][k] + dp[son][j-k]);
}
}
}
}
int main()
{
while(~scanf("%d%d" , &n , &m)){
if(n == 0 && m == 0)
break;
m++;//m要加1因为要多选择一个0节点
for(int i = 0 ; i <= n ; i ++)
tree[i].clear();
memset(dp , 0 , sizeof(dp));
for(int i = 1 ; i <= n ; i ++){
int sign , val;
scanf("%d%d" , &sign , &val);
tree[sign].push_back(i);
for(int j = 1 ; j <= m ; j ++){
dp[i][j] = val ;
}
}
dfs(0);
printf("%d\n" , dp[0][m]);
}
return 0;
}