poj 2486 Apple Tree 夜

http://poj.org/problem?id=2486

树形DP 我一般都是先用邻接表保存树 然后用的都是子树和所有兄弟树的dp方法

自己感觉理解也行呀 但是没见有多少人用呢,也许自己有点另类

老是出错 思维能力还是不够 越来越感觉acm是在练一个人的思维了

题目大意:

给一个树 节点有一定数目的苹果

人在1(根点)最多走K步 问最多可以得到多少苹果

思路:

ans[i][j][0] 表示包括i在内所以其子节点和右边兄弟树 可以走j步 可以存在不回来的情况 的最佳答案

ans[i][j]][1] 这个必须都回来

代码及其注释:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<cmath>
#include<stack>
#include<algorithm>
#define LL long long

using namespace std;

const int N=105;
const int MIN=-100000000;
struct node
{
    struct tt *next;
}mem[N];
struct tt
{
    int j;
    struct tt *next;
};
bool had[N];
bool link[N][N];
int applenum[N];
int ans[N][N*2][2];
int a[3][3][3];
void build(int i,int j)
{
    struct tt *t=new tt;
    t->j=j;
    t->next=mem[i].next;
    mem[i].next=t;
}
void Dele(int n)
{
    struct tt *t;
    for(int i=1;i<=n;++i)
    {//cout<<i<<endl;
        while(mem[i].next!=NULL)
        {//cout<<"iii"<<endl;
            t=mem[i].next;
            mem[i].next=t->next;
            delete t;
        }
    }
}
int dp(struct tt *t,int k,int back)
{
   if(t==NULL)//各种 无法走的情况
   return 0;
   if(k<0)
   return 0;
   if(back==1&&k<1)
   return 0;
   if(ans[t->j][k][back]!=-1)
   return ans[t->j][k][back];
   int itemp=0;
   int w=0;
   for(int i=0;i<=k;++i)
   {
       if(i>=1)
       w=applenum[t->j];//要回去时 只有可以回去 才能加上本节点的苹果树
       itemp=max(itemp,w+dp(mem[t->j].next,i-2,1)+dp(t->next,k-i-1,back));//给子树一部分 往兄弟传一部分 注意路径需要的步数减去
       if(back==0)
       {
           w=applenum[t->j];//这是子树不用回来的 其他差不多
           itemp=max(itemp,w+dp(mem[t->j].next,i-1,0)+dp(t->next,k-i-1,1));
       }
   }
   ans[t->j][k][back]=itemp;
   if(t->next!=NULL)
   ans[t->j][k][back]=max(ans[t->j][k][back],dp(t->next,k,back));//如果不走此节点
   return  ans[t->j][k][back];
}
void dfs(int x,int n)
{
    had[x]=true;
    for(int i=1;i<=n;++i)
    {
        if(link[x][i]&&!had[i])
        {
            build(x,i);//建立单向树
            dfs(i,n);
        }
    }
}
int main()
{
    int n,k;
    while(scanf("%d %d",&n,&k)!=EOF)
    {
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&applenum[i]);
        }
        memset(link,false,sizeof(link));
        for(int i=1;i<n;++i)
        {
            int x,y;
            scanf("%d %d",&x,&y);
            link[x][y]=link[y][x]=true;
        }
        if(n==1)
        {
            printf("%d\n",applenum[1]);
            continue;
        }
        memset(had,false,sizeof(had));
        dfs(1,n);
        memset(ans,-1,sizeof(ans));
        printf("%d\n",applenum[1]+dp(mem[1].next,k-1,0));
        Dele(n);
    }
}

  

原文地址:https://www.cnblogs.com/liulangye/p/2605514.html