这题写的我好纠结啊,过程中各种思路混乱,树P太弱了。。。dp[i][j]表示到i节点为根的子树有j元能得到的最小伤害的最大值,转移的话就是个一维背包,我是先做子树最后处理这个节点本身的权值的,需要注意price为0的节点,这地方坑了我两次,每个节点有多少钱的时候最多能得到多少伤害需要预处理出来。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#define N 1005
using namespace std;
vector<int>e[N];
vector<pair<int,int> >p[N];
int dp[N][205],kk[N],ok[N][205];
int n,m;
void dfs(int u,int fa)
{
int flag = 0;
for(int i = 0; i<e[u].size(); i++)
{
int v = e[u][i];
if(v == fa)continue;
dfs(v,u);
if(flag == 0)
{
for(int j = 0;j<=m;j++)
dp[u][j] = dp[v][j];
flag = 1;
continue;
}
for(int j = m; j>=0; j--)
{
dp[u][j] = min(dp[u][j],dp[v][0]);
for(int k = 1; k<=j; k++)
dp[u][j] = max(dp[u][j],min(dp[u][k],dp[v][j-k]));
}
}
for(int i = m;i>=0;i--)
{
int Max = 0;
for(int j = 0; j<=i; j++)
Max = max(dp[u][j]+ok[u][i-j],Max);
dp[u][i] = max(dp[u][i],Max);
}
}
int main()
{
int t,i,j,k;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(i = 1; i<=n; i++)
{
e[i].clear();
p[i].clear();
}
for(i = 1; i<n; i++)
{
int u,v;
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
memset(ok,0,sizeof(ok));
scanf("%d",&m);
for(i = 1; i<=n; i++)
{
scanf("%d",&kk[i]);
for(j = 1; j<=kk[i]; j++)
{
int x,y;
scanf("%d%d",&x,&y);
for(k = 0;k<=m;k++)if(x<=k)ok[i][k] = max(ok[i][k],y);
p[i].push_back(make_pair(x,y));
}
}
memset(dp,0,sizeof(dp));
dfs(1,-1);
printf("%d\n",dp[1][m]);
}
return 0;
}