【树形DP】 POJ 2486 Apple Tree

来源:互联网 发布:京东购物流程淘宝 编辑:程序博客网 时间:2024/06/06 03:22

题目链接:  POJ 2486 Apple Tree

分析: 

      这题最重要的一个地方是可能会走回头路.

      那么,我们对某一结点可分为两种状态, 即访问其子结点后回来及不回来.

      当访问到某一结点的子结点时, 有以下三种情况:

      PS. dp[u][i][j]  表示到结点i已经走了j步,得到最多的苹果数. u=0 表示不回到该结点, u=1是回到该点.

      Ⅰ、从兄弟结点出发访问son结点, 要经过cnt,所以要+2到达son. 并且不再回到cnt.

      

     


      Ⅱ、直接从父亲访问son结点,所以到达son只需要 +1, 并且不再回到父亲结点

       


      Ⅲ、直接从cnt结点访问son结点, 访问son的整个树枝之后又回到父亲结点. 因些要+2.

     

      



代码:


#include<iostream>#include<cstdio>#include<cstring>#include<vector>using namespace std;const int maxn=222;vector<int>Tree[maxn];int dp[2][maxn][maxn];  /// 1表示去过子结点回到原来的点, 0相反int val[maxn];bool vis[maxn];int n,m;void DFS(int cnt){    vis[cnt]=true;    int len=Tree[cnt].size();    for(int i=0;i<=m;++i)        dp[0][cnt][i]=dp[1][cnt][i]=val[cnt];    for(int i=0;i<len;++i){        int son=Tree[cnt][i];        if(vis[son]) continue;        DFS(son);        for(int j=m;j>=0;--j)            for(int k=0;k<=j;++k){                dp[0][cnt][j+1]=max(dp[0][cnt][j+1],dp[1][cnt][j-k]+dp[0][son][k]);                dp[0][cnt][j+2]=max(dp[0][cnt][j+2],dp[0][cnt][j-k]+dp[1][son][k]);                dp[1][cnt][j+2]=max(dp[1][cnt][j+2],dp[1][cnt][j-k]+dp[1][son][k]);            }    }}int main(){    while(~scanf("%d%d",&n,&m)){        memset(dp,0,sizeof(dp));        memset(vis,0,sizeof(vis));        for(int i=1;i<=n;++i){            Tree[i].clear();            scanf("%d",&val[i]);        }        for(int i=1;i<n;++i){            int a,b; scanf("%d%d",&a,&b);            Tree[a].push_back(b);            Tree[b].push_back(a);           }        DFS(1);        printf("%d\n",dp[0][1][m]);    }    return 0;}





原创粉丝点击