你想吃苹果就吃,为什么要爬树。
题意
一棵N个点的树,每个点有一个值a[i],点编号为1~N,问从点1出发,一共走K步,共能获取多少a值。每个a值只能获取一次。
输入输出
Input
There are several test cases in the 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.
Input will be ended by the end of file.
Note: Wshxzt starts at Node 1.
Output
For each test case, output the maximal numbers of apples Wshxzt can eat at a line.
分析
dp[i][j][k]表示以i为根的子树,在上面共走j步,k为1则最后必须回到i点,k为0则不需回到i点。
状态转移见代码。
有两个容易错的地方,一个是可能不需要走K步就可以得到最优解,然而DP没有进行到下标为K的点因此DP[1][K][]可能还是初始值。第二个是由于遍历一个点的儿子是有序的,我拉掉了先遍历到k值为0,后遍历到k值为1的情况,只要加上这种情况的状态转移即可,不需讨论儿子的排序。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define mxn 110
#define mxk 210
#define inf 0x3f3f3f3f
int n,K;
int a[mxn];
bool mapp[mxn][mxn];
int first[mxn],nxt[mxn],vv[mxn],cnt;
int dp[mxn][mxk][2];
void add(int u,int v){
nxt[cnt]=first[u];
first[u]=cnt;
vv[cnt++]=v;
}
void build_tree(){
bool flag[mxn];
memset(flag,false,sizeof(flag));
memset(first,-1,sizeof(first));
cnt=0;
int q[mxn];
int head=0,tail=1;
q[head]=1, flag[1]=true;
while(head<tail){
int now=q[head++];
for(int i=1;i<=n;++i) if(!flag[i]&&mapp[now][i]){
flag[i]=true;
q[tail++]=i;
add(now,i);
}
}
}
void dfs(int now){
dp[now][0][1]=a[now];
for(int i=first[now];i!=-1;i=nxt[i]){
dfs(vv[i]);
for(int j=K;j>=0;--j){
for(int k=0;k<j-1;++k){
dp[now][j][1]=max(dp[now][j][1],dp[now][j-k-2][1]+dp[vv[i]][k][1]);
dp[now][j][0]=max(dp[now][j][0],dp[now][j-k-2][0]+dp[vv[i]][k][1]);
dp[now][j][0]=max(dp[now][j][0],dp[now][j-k-1][1]+max(dp[vv[i]][k][1],dp[vv[i]][k][0]));
}
dp[now][j][0]=max(dp[now][j][0],dp[now][0][1]+max(dp[vv[i]][j-1][1],dp[vv[i]][j-1][0]));
}
}
}
int DP(){
for(int i=0;i<mxn;++i)
for(int j=0;j<mxk;++j)
for(int k=0;k<2;++k)
dp[i][j][k]=-inf;
dfs(1);
int ret=0;
for(int i=0;i<=K;++i) ret=max(ret,max(dp[1][i][0],dp[1][i][1]));
return ret;
}
int main(){
while(scanf("%d%d",&n,&K)!=EOF){
for(int i=1;i<=n;++i) scanf("%d",a+i);
memset(mapp,false,sizeof(mapp));
for(int i=1;i<n;++i){
int u,v;
scanf("%d%d",&u,&v);
mapp[u][v]=mapp[v][u]=true;
}
build_tree();
printf("%d\n",DP());
}
return 0;
}