POJ_2486_Apple Tree_树状DP

你想吃苹果就吃,为什么要爬树。

题意

一棵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;
}
点赞