您的位置:首页 > 其它

【codevs1163】访问艺术馆,圣战の终焉

2015-11-05 15:18 260 查看
访问艺术馆

时间限制: 1 s

空间限制: 128000 KB

题目等级 : 大师 Master

题解

题目描述 Description

皮尔是一个出了名的盗画者,他经过数月的精心准备,打算到艺术馆盗画。艺术馆的结构,每条走廊要么分叉为二条走廊,要么通向一个展览室。皮尔知道每个展室里藏画的数量,并且他精确地测量了通过每条走廊的时间,由于经验老道,他拿下一副画需要5秒的时间。你的任务是设计一个程序,计算在警察赶来之前(警察到达时皮尔回到了入口也算),他最多能偷到多少幅画。



输入描述 Input Description

第1行是警察赶到得时间,以s为单位。第2行描述了艺术馆得结构,是一串非负整数,成对地出现:每一对得第一个数是走过一条走廊得时间,第2个数是它末端得藏画数量;如果第2个数是0,那么说明这条走廊分叉为两条另外得走廊。数据按照深度优先得次序给出,请看样例

输出描述 Output Description

输出偷到得画得数量

样例输入 Sample Input

60

7 0 8 0 3 1 14 2 10 0 12 4 6 2

样例输出 Sample Output

2

数据范围及提示 Data Size & Hint

s<=600

走廊的数目<=100

写在前面:自此,钻石天梯全部搞完,在noip前一天进入大师,求rp++

————————————————————————————————————————————————————————

解题思路:这里我真的不太想写,因为我的树型dp学的很渣很渣,这道题目也是看了别人的blog才知道如何实现建树(之前只知道是什么,但不知道具体怎么写),数据给出的就是dfs下的节点顺序,加上记忆化搜索就可以了。

(还是说一下dp思路吧,f[i][j]指到达第i个节点且还有j个时间单位下最大价值是多少,对于任意一个非叶节点i,它在j时间下的最大价值为f[i][j]=max(f[i][j],f[i的左儿子][t]+f[i的右儿子][j-t],t为循环变量,代表着分给左右儿子不同的时间得到不同的价值,取价值即可;如果是叶节点,那么我们只要判断分配给这个叶节点的时间够偷几幅画就可以了(时间够就全偷))

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int n,f[1000][1000],now=1;
bool flag[1000][1000];//判断该状态之前是否已经找到过,避免重复搜索
int tot;
struct os
{
int l,r,w,v;//左右儿子,代价,价值
}a[100000];
void build_tree()
{
int k=now;
if (a[k].v!=0) return;
a[k].l=++now;
build_tree();
a[k].r=++now;
build_tree();
}
void dfs(int x,int remain)
{
if (flag[x][remain]) return;//之前有过就返回
int t=remain-a[x].w;//真正能分配给左右儿子或偷画的时间t
if (t<=0) return;
if (a[x].l==a[x].r)
f[x][remain]=min(t/5,a[x].v);//全偷or尽可能偷
else
for (int i=0;i<=t;i++)
{
dfs(a[x].l,i);
dfs(a[x].r,t-i);
f[x][remain]=max(f[x][remain],f[a[x].l][i]+f[a[x].r][t-i]);
}
flag[x][remain]=true;
}
main()
{
scanf("%d",&tot);
int x,y;
while (scanf("%d%d",&x,&y)!=EOF)
a[++n].w=x*2,a
.v=y;
build_tree();
dfs(1,tot);
printf("%d",f[1][tot]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: