【树形DP】wikioi 1163 访问艺术馆

题目来源: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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值