题目来源:http://wikioi.com/problem/1163/
分析:
树状动态规划。
用树存储艺术馆内的情况,然后从根到叶递归求解。对于每个节点,将可用时间分给他的左右儿子,枚举所有分法,取最大值。最后输出根节点的数值即可。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#define maxn 301
#define maxt 601
using namespace std;
struct node{
int t,ls,rs,v;
}te[maxn]; //储存树的信息
int a[maxn][2],f[maxn][maxt],m=0,i,ti;
void build(int r) //递归建树
{
te[r].t=2*a[r][0];
te[r].v=a[r][1];
if (a[r][1]!=0)
{
te[r].ls=te[r].rs=-1;
return;
}
te[r].ls=++m;build(m);
te[r].rs=++m;build(m);
}
int dfs(int r,int i)
{
if (f[r][i]!=-1) return f[r][i]; //如果已有值,直接返回
if (i==0) return f[r][i]=0; //时间没了,返回
if (te[r].ls==-1)
{
if (te[r].v*5<i-te[r].t) return te[r].v; //能拿完
else return (i-te[r].t)/5; //不能拿完
}
int lt,rt;
for (lt=0;lt<=i-te[r].t;lt++) //枚举不同分法
{
rt=i-te[r].t-lt;
int s1=dfs(te[r].ls,lt);
int s2=dfs(te[r].rs,rt);
f[r][i]=max(f[r][i],s1+s2);
}
return f[r][i];
}
int main()
{
memset(f,-1,sizeof(f));
scanf("%d",&ti);
while (scanf("%d%d",&a[i][0],&a[i][1])!=EOF) i++;
build(m);
printf("%d",dfs(0,ti));
return 0;
}