M_sea

洛谷1270 “访问”美术馆
Luogu算法这是一道树形DP。设 $f[i] [j]$ 表示当前节点为 $i$ 用掉 $j$ 秒所取得的最大值。...
扫描右侧二维码阅读全文
06
2017/10

洛谷1270 “访问”美术馆

Luogu

算法

这是一道树形DP。

设 $f[i] [j]$ 表示当前节点为 $i$ 用掉 $j$ 秒所取得的最大值。

那么当这条走廊通向叶子节点 $i$时:

if (i是叶子节点) f[i][j]=max(i的画数,(j-该走廊通过时间)/5);

否则枚举左子树时间,分配给左右子树取和的最大值:

for (re int k=0;k<=time-tree[now].time;k++)
    f[now][time]=max(f[now][time],Dfs(now<<1,k)+Dfs(now<<1|1,time-tree[now].time-k));

直接记搜即可。

代码

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define re register
using namespace std;
inline int read() //读优
{
    int X=0,w=1; char ch=getchar();
    while (ch<'0'||ch>'9') { if (ch=='-') w=-1; ch=getchar(); }
    while (ch>='0'&&ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
    return X*w;
}
struct node //树节点
{
    int time,sum;
    node() { this->time=this->sum=0; }
}tree[10010];
int n,cnt=0;
inline void build(int now) //建树,说明见上
{
    tree[now].time=read()*2; tree[now].sum=read();
    if (tree[now].sum!=0) return;
    else { build(now<<1); build(now<<1|1); }
}
int f[1010][1010]; //f[i][j]表示当前节点为i用掉j秒所取得的最大值
inline int Dfs(int now,int time) //now表示当前节点,time表示剩余时间
{
    if (f[now][time]||!time) return f[now][time]; //记搜边界,计算过或没时间了
    if (tree[now].sum) { f[now][time]=min(tree[now].sum,(time-tree[now].time)/5); return f[now][time]; }
    //叶子节点处理
    for (re int k=0;k<=time-tree[now].time;k++) //枚举一下左子树的时间,分别计算左右子树,再加起来取max
        f[now][time]=max(f[now][time],Dfs(now<<1,k)+Dfs(now<<1|1,time-tree[now].time-k));
    return f[now][time]; //返回
}
int main()
{
    n=read()-1; //注意这里要-1
    build(1); //建树
    printf("%d\n",Dfs(1,n)); //直接Dfs输出
    return 0;
}
最后修改:2019 年 05 月 26 日 02 : 18 PM

发表评论