访问艺术馆

【题目描述】

John打算到艺术馆盗画,在艺术馆里,每条走廊要么分叉为两条走廊,要么通向一个展览室(走廊的数目 <= 100)。John知道每个展览室藏画的数量,以及通过每条走廊所用的时间,并且他拿下一副画需要5秒钟的时间。

现询问在警察赶来之前,John最多能够偷到多少幅画。

【输入描述】

第一行输入一个数,表示警察赶到的时间S(S <= 600);

第二行输入一行非负整数,每一对数的第一个数表示通过一条走廊所需的时间,第二个数表示其末端的藏画数量,如果第二个数为0,那么说明这条走廊分叉为两条走廊,数据按深度优先次序给出。

【输出描述】

输出一个数,表示答案。

【样例输入】

60

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

【样例输出】

2

源代码:

#include<cstdio>
#include<algorithm>
using namespace std;
struct Node
{
    int Sum,Time,Left,Right;
}i[101];
int S,Num(0),Q[101],f[601][601];
void Build(int T)
{
    int t;
    scanf("%d%d",&i[T].Time,&t);
    Num++;
    if (!t)
    {
        i[T].Left=Num;
        Build(i[T].Left);
        i[T].Right=Num;
        Build(i[T].Right);
    }
    else
      i[T].Sum=t;
}
int main()
{
    scanf("%d",&S);
    S--; //迷之题意。
    Build(0); //DFS序建树。
    int Head=0,Tail=1;
    Q[0]=0;
    while (Head<Tail) //DFS序遍历。
    {
        int t=Q[Head++];
        if (i[t].Left)
          Q[Tail++]=i[t].Left;
        if (i[t].Right)
          Q[Tail++]=i[t].Right;
    }
    for (int a=Tail-1;a>=0;a--) //从底层开始DP。
    {
        int t=Q[a];
        if (!i[t].Left&&!i[t].Right) //叶子节点。
          for (int b=2*i[t].Time;b<=S;b++)
            f[b][t]=min((b-2*i[t].Time)/5,i[t].Sum);
        else //中间节点。
          for (int b=2*i[t].Time;b<=S;b++)
            for (int c=0;c<=b-2*i[t].Time;c++)
              f[b][t]=max(f[b][t],f[c][i[t].Left]+f[b-2*i[t].Time-c][i[t].Right]);
    }
    printf("%d",f[S][0]);
    return 0;
}

/*
    设f[i][j]表示以j为根节点,用时i所能偷到画的最大数量,并且此模型为二叉树,则有状态转移方程:
        f[i][j]=max(f[k][j.Left]+f[i-2*j.Time-k][j.Right])
    动态规划的循环顺序真可谓神通广大,orz。
*/

 

posted @ 2016-10-19 15:34  前前前世。  阅读(221)  评论(0编辑  收藏  举报