访问艺术馆
【题目描述】
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。 */