“访问”美术馆

传送门

这是一道神奇的树形DP,对它还是不需要建树,而且完全可以一边读入,一边DP出结果……

首先我们看题目描述很显然是一棵二叉树,而且还是完全二叉树。(没啥卵用)

令dp[i][j]表示在第i个节点选取花费j时间所能获取的最大画数。

之后因为题目的输入是递归给出的……所以我们直接去建图难度很大,不妨直接边递归边求解。首先我们考虑,如果当前的节点是一个不会再分裂的点(他下面直接通向展览馆)。我们直接更新这个节点的答案就可以。

之后如果他要能再分裂,先递归下去,之后在返回的途中,枚举对于左子树给其分配的偷窃时间,这样进行合并就可以啦。

注意因为这哥们偷完东西得跑出去,所以相当于每条道路的权值要<<1,还有就是他必须在警察来之前1秒必须跑出去,所以读入要--。

然后就可以做了。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#include<set>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')

using namespace std;
typedef long long ll;
const int M = 100005;

int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-') op = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
    }
    return ans * op;
}


int cnt,tot,n,m,dp[105][605];

void dfs()
{
    int ro = ++cnt,lim;
    lim = read(),tot = read(),lim <<= 1;
    if(tot) rep(t,lim,n) dp[ro][t] = min((t-lim) / 5,tot);//已经到展览馆就更新
    else
    {
        int l = cnt+1;dfs();
        int r = cnt+1;dfs();
        rep(t,lim,n)
        rep(lt,0,t-lim)
        dp[ro][t] = max(dp[ro][t],dp[l][lt] + dp[r][t-lt-lim]);//更新答案
    }
}

int main()
{
    n = read(),n--;
    dfs();
    printf("%d\n",dp[1][n]); 
    return 0;
}

 

posted @ 2018-09-12 20:34  CaptainLi  阅读(186)  评论(0编辑  收藏  举报