昨天一个下午边看视频边写的代码,今天又一个下午来调试,本来对这份代码很没信心的,觉得那些想法有问题,今天跟同学又讨论了一下午找代码里的Bug,把程序认认真真读了一遍之前写的那些想法都明白了:树形DP,分组背包空间优化,建树,DP状态转移过程中的“滚动数组”。 觉得对DP有了更深入的理解吧,代码发上来纪念下。
最后膜拜下政哥……
#include <iostream>
#include <memory.h>
#include <vector>
#include <cstdio>
using namespace std;
vector<int> edge[1005];
vector<int> price[1005];
vector<int> power[1005];
int n,m,par[1005],dp[1005][205];
void init()
{
for(int i=0; i<=n; i++) edge[i].clear();
for(int i=0; i<=n; i++) price[i].clear();
for(int i=0; i<=n; i++) power[i].clear();
memset(par,0,sizeof(par));
memset(dp,0,sizeof(dp));
}
void dfs(int curr)
{
int tmp,len = edge[curr].size();
for(int i=0; i<len; i++)
{
if(edge[curr][i]!=par[curr])
{
par[edge[curr][i]] = curr; // 标记父亲结点建树
dfs(edge[curr][i]);
}
}
tmp = 0;
if(len>1)
{
if(edge[curr][tmp]==par[curr]) tmp=1;
for(int i=0;i<=m;i++) dp[curr][i]=dp[edge[curr][tmp]][i]; //用孩子的第一个结点对当前结点孩子的分组背包进行初始化
}
for(int i=tmp+1; i<len; i++)
{
if(edge[curr][i]!=par[curr])
{
for(int v=m; v>=0; v--)
{
int ans = 0; // 一定要另开个ans,我以前直接用的dp[curr][v]果断有问题
for(int j=0; j<=v; j++)
{
ans=max(ans,min(dp[curr][v-j],dp[edge[curr][i]][j]));
}
dp[curr][v] = ans;
}
}
}
for(int v=m; v>=0; v--)
{
int ans = dp[curr][v]; // 一定要用ans,而且ans不能赋值为0,因为当前结点可以没有塔
for(int i=0; i<price[curr].size(); i++)
{
if(v>=price[curr][i])
{
ans = max(ans,dp[curr][v-price[curr][i]]+power[curr][i]);
}
}
dp[curr][v] = ans;
}
}
int main()
{
int k,a,b,c,maxVal;
while(scanf("%d",&k)!=EOF)
{
while(k--)
{
init();
scanf("%d",&n);
for(int i=1; i<n; i++)
{
scanf("%d%d",&a,&b);
edge[a].push_back(b);
edge[b].push_back(a); // 双向建边
}
edge[1].push_back(0);
scanf("%d",&m);
for(int i=1; i<=n; i++)
{
scanf("%d",&c);
while(c--)
{
scanf("%d%d",&a,&b);
price[i].push_back(a);
power[i].push_back(b);
}
}
dfs(1);
maxVal = 0;
for(int i=0; i<=m; i++)
{
if(dp[1][i]>maxVal) maxVal=dp[1][i];
}
printf("%d\n",maxVal);
}
}
return 0;
}