1019. Apple Tree
Constraints
Time Limit: 1 secs, Memory Limit: 32 MB
Description
Wshxzt is a lovely girl. She likes apple very much. One day HX takes her to an apple tree. There are N nodes in the tree. Each node has an amount of apples. Wshxzt starts her happy trip at one node. She can eat up all the apples in the nodes she reaches. HX is a kind guy. He knows that eating too many can make the lovely girl become fat. So he doesn’t allow Wshxzt to go more than K steps in the tree. It costs one step when she goes from one node to another adjacent node. Wshxzt likes apple very much. So she wants to eat as many as she can. Can you tell how many apples she can eat in at most K steps.
Input
Each test case contains three parts.
The first part is two numbers N K, whose meanings we have talked about just now. We denote the nodes by 1 2 … N. Since it is a tree, each node can reach any other in only one route. (1<=N<=100, 0<=K<=200)
The second part contains N integers (All integers are nonnegative and not bigger than 1000). The ith number is the amount of apples in Node i.
The third part contains N-1 line. There are two numbers A,B in each line, meaning that Node A and Node B are adjacent.
Note: Wshxzt starts at Node 1.
Output
For each test case, output the maximal numbers of apples Wshxzt can eat at a line.
Sample Input
2 1 0 11 1 2 3 2 0 1 2 1 2 1 3
Sample Output
11 2
Problem Source
ZSUACM Team Member
苹果树可以抽象成树形数据结构,直接暴力法会超时,考虑用动态规划,这个树形dp的状态转移方程比较难理解。由于对于每一例,有出发节点,最大步数,是否回到出发点三个状态参量,所以可以用一个三维数组要表示最大权重,即dp[i][j][0]表示从i出发走j步且不会到i点的最大权重,dp[i][j][1]表示最后回到i点的最大权重。关于状态转移方程有:
dp[pos][j][1]=max(dp[pos][j][1],dp[pos][j-k][1]+dp[LINK[pos][i]][k-2][1]);
从pos节点出发走了j-k步回到pos节点,再从pos出发走k步回到pos,由于pos处的权重不能重复计算,所以第二部分可直接记成从pos的子节点出发而后又回到子节点再返回pos,所以除去从pos到子节点以及从子节点返回pos的两步,从子节点直接出发共走了k-2步。
dp[pos][j][0]=max(dp[pos][j][0],dp[pos][j-k][1]+dp[LINK[pos][i]][k-1][0]);
同理,此次由于不返回pos节点,所以只用除去从pos到子节点的一步,从子节点出发共走了k-1步且最后不返回子节点。
dp[pos][j][0]=max(dp[pos][j][0],dp[pos][j-k][0]+dp[LINK[pos][i]][k-2][1]);
第二种不返回pos的情况(先走子节点),从pos的子节点出发然后再从子节点返回了pos,共k步,所以子节点走了k-2步,但是再从pos出发时不返回pos。
以此递推关系为核心,可以用dfs递归来确定各个dp[i][j][1]([0]),然后dp[1][K][1]或[0]中较大的那个就是最终答案。具体详见代码注释。
#include<iostream>
#include<vector>
#include<cmath>
#include<cstdlib>
using namespace std;
vector<int> LINK[110];//vector容器数组,用来节点的联接关系,例如与节点1相连的节点序号存储在LINK[1]容器中
int weight[110];//保存每个节点的权重
int N,K;//题中所给的总节点N和最大步数K
int dp[110][220][2];//动态规划的状态函数,第一个下标表示起始节点,第二个表示最大步数,第三个表示最后是否回到起始点,即dp[i][j][1]表示从i出发走j步且最后回到i所能获得的最大权重
void makeT()
{
for(int i=1;i<=N;++i)
LINK[i].clear();//清空联结关系
for(int i=1;i<=N;++i)
{
cin>>weight[i];
for(int j=0;j<=K;++j)
{
dp[i][j][1]=dp[i][j][0]=weight[i];//对dp状态函数进行初始化
}
}
int node1,node2;
for(int i=1;i<N;++i)
{
cin>>node1>>node2;
LINK[node1].push_back(node2);//建立联结关系
LINK[node2].push_back(node1);
}
}
void dfs(int pos,int end)//用深搜递归的方法来确定dp数组,pos为出发的节点,end为pos节点的父节点。
{
for(int i=0;i<LINK[pos].size();++i)
{
if(LINK[pos][i]==end) continue;
dfs(LINK[pos][i],pos);//确定了pos的一个子树的dp数组值
for(int j=K;j>=1;--j)
{
for(int k=1;k<=j;++k)
{
dp[pos][j][1]=max(dp[pos][j][1],dp[pos][j-k][1]+dp[LINK[pos][i]][k-2][1]);//dp状态转移方程
dp[pos][j][0]=max(dp[pos][j][0],dp[pos][j-k][1]+dp[LINK[pos][i]][k-1][0]);
dp[pos][j][0]=max(dp[pos][j][0],dp[pos][j-k][0]+dp[LINK[pos][i]][k-2][1]);
}
}
}
}
int main()
{
while(cin>>N>>K)
{
makeT();
dfs(1,0);
cout<<max(dp[1][K][1],dp[1][K][0])<<endl;//比较从1出发走K步最后回到1和不回到1的最大权重值,较大的即为最终结果
}
return 0;
}
4680

被折叠的 条评论
为什么被折叠?



