题意:有一颗苹果树,每个节点有一些苹果,问从根节点出发走K步最多能吃到多少苹果。
题解:树形DP,状态转移较为复杂,具体可参考注释。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
class solve
{
private:
vector<vector<int> > sons;
char* vis;
int** dp[2];
int N,K;
int maxVal;
public:
solve(int n,int k):N(n),K(k)
{
sons.resize(N+1);
vis = new char[N+1];
memset(vis,0,sizeof(char)*(N+1));
dp[0] = new int*[N+1];
//从父节点出发要返回父节点走i步能吃到的最多苹果
dp[1] = new int*[N+1];
//从父节点出发不用返回父节点走i步能吃到的最多苹果
if(K >= 2*(N-1))
//超过最多的步数,可能未更新导致WA
{
K = 2*(N-1);
}
for(int i = 1;i <= N;i++)
{
dp[0][i] = new int[K+2];
dp[1][i] = new int[K+2];
memset(dp[0][i],0XDF,sizeof(int)*(K+2)); //设置极小值,但是两极小值相加又不会溢出为正数
memset(dp[1][i],0XDF,sizeof(int)*(K+2));
}
processIn();
DFS(1);
maxVal = max(dp[0][1][K],dp[1][1][K]);
printf("%d\n",maxVal);
}
~solve()
{
vector<vector<int> >().swap(sons);
delete[] vis;
delete[] dp[0];
delete[] dp[1];
}
int processIn();
int DFS(int fa);
};
int solve::DFS(int fa)
{
vis[fa] = 1;
int sonSize = sons[fa].size();
for(int i = 0;i < sonSize;i++)
{
int son = sons[fa][i];
if(vis[son])
//不能访问父节点及祖先节点
continue;
DFS(son);
for(int j = K-1;j >= 0;j--)
//倒序,使用上个子节点的数据
{
for(int k = 0;k <= j;k++)
{
dp[0][fa][j+2] = max(dp[0][fa][k]+dp[0][son][j-k],dp[0][fa][j+2]);
//要返回fa,从son出发也必须返回son
dp[1][fa][j+2] = max(dp[1][fa][k]+dp[0][son][j-k],dp[1][fa][j+2]);
//不返回fa,fa->son->son->fa->others son
dp[1][fa][j+1] = max(dp[0][fa][k]+dp[1][son][j-k],dp[1][fa][j+1]);
//不返回fa,fa->others son->others son->fa->son
}
}
}
return 0;
}
int solve::processIn()
{
for(int i = 1;i <= N;i++)
{
scanf("%d",dp[0][i]);
dp[1][i][1] = dp[0][i][2] = dp[1][i][0] = dp[0][i][0]; //初始节点的最少收益
}
int fa,son;
for(int i = 1;i < N;i++)
{
scanf("%d%d",&fa,&son);
sons[fa].push_back(son);
sons[son].push_back(fa);
}
return 0;
}
int main()
{
int n,k;
while(~scanf("%d%d",&n,&k))
{
solve poj_2486(n,k);
}
return 0;
}