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

来源:互联网 发布:淘宝系统繁忙 编辑:程序博客网 时间:2024/04/30 15:42

访问艺术馆
时间限制: 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[n].v=y;    build_tree();    dfs(1,tot);    printf("%d",f[1][tot]);}
0 0
原创粉丝点击