CODEVS1163访问艺术馆(第一道大师水题)

 题目描述  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

思路:首先读懂题意,不一定要取完一个画室中的画,取一幅画要5s,没看到这两件事,让我蛋疼的写了个简单的深搜,结果。。。错了。。。
先用递归建树,保存一下父节点,儿子节点,到父亲的距离,自己末端的画数(有的变量可能用不到)。然后开始树状dp,f[i][j]表示第i个节点取j幅画,然后对左右子树进行选择。一点点的算出来。
注意每次循环就是从0-该子树最多的画数(用一个数组保存一下),还有一点,work时,从0开始递归,因为input时把1的父节点默认为了0。。。(这个肮脏的错误让我很。。。)  

code:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
struct use{
int fa,d,va,l,r;
}a[1000];
int s,n=0,su[500]={0},ans=0;
long long f[500][10000]={0};
void input(int faa)
{
int x,y,t;
cin>>x>>y;
++n;t=n;
if (a[faa].l==0) a[faa].l=n;
else a[faa].r=n;
a[n].fa=faa;
a[n].d=x*2;
if (y==0)
{
input(t);
input(t);
}
else
  a[t].va=y;
}
void work(int i)
{
int j,k,l1,l2;
if (a[i].l==0) 
{
su[i]=a[i].va;
for (j=1;j<=a[i].va;++j)
  f[i][j]=5*j;
return;
    }
work(a[i].l);
if (i!=0)
  work(a[i].r);
f[i][0]=0;
for (k=1;k<=su[a[i].r];++k)
  f[i][k]=min(f[i][k],f[a[i].r][k]+a[a[i].r].d);
for (j=1;j<=su[a[i].l];++j)
  f[i][j]=min(f[i][j],f[a[i].l][j]+a[a[i].l].d);
for (j=1;j<=su[a[i].l];++j)
  for (k=1;k<=su[a[i].r];++k)
     f[i][j+k]=min(f[i][j+k],f[a[i].l][j]+a[a[i].l].d+a[a[i].r].d+f[a[i].r][k]);
su[i]=su[a[i].l]+su[a[i].r];
}
int main()
{
int i,j;
cin>>s;
memset(a,0,sizeof(a));
memset(f,127,sizeof(f));
    input(0);
    work(0);
    for (i=1;i<=su[0];++i)
      if (f[0][i]<=s&&i>ans) ans=i;
    cout<<ans<<endl;
}    

你可能感兴趣的:(code)