[洛谷P3360]偷天换日

偷天换日

题目描述

神偷对艺术馆内的名画垂涎欲滴准备大捞一把。艺术馆由若干个展览厅和若干条走廊组成。每一条走廊的尽头不是通向一个展览厅,就是分为两个走廊。每个展览厅内都

有若干幅画,每幅画都有一个价值。经过走廊和偷画都是要耗费时间的。警察会在第n秒到达进口,在不被逮捕的情况下你最多能得到的价值

输入格式

第一行一个整数 n

第二行若干组整数,对于每组整数(t,x),t表示进入这个展览厅或经过走廊要耗费t秒的时间,若x>0表示走廊通向的展览厅内有x幅画,接下来x对整数(w,c)表示偷一幅价值为w的画需要c秒的时间。若x=0表示走廊一分为二。

输入是按深度优先给出的。

输出格式

仅一个整数,表示能获得的最大价值。

样例

样例输入

50
5 0 10 1 10 1 5 0 10 2 500 1 1000 2 18 1 1000000 4

样例输出

1500

数据范围与提示

n≤600;t,c≤5;x≤30

房间和走廊数不超过300个。

注意题目要求你在不被逮捕的情况下得到最多的价值

样例的输入对应于下图

image

一开始打纯暴力,看出来了是背包,打了纯01背包的循坏和转移方程,想出来背包之后就被输入给恶心到了,没有数据的限制,纯读入有想到要像建线段树那样递归读入,但是没想到可满足的递归方法,就直接读入到了不同的数组,算是记录了每个点的权值和花费。然后就直接打了01背包,试数据不对,又接着调试,发现直接打01背包会忽略要走到画所在的展厅花费的时间,又想到记录走到这个点花费的时间,就有了记录前驱和每个点有没有紧连着的展厅以及个数(dfs序读入很恶心,走廊分叉不能直接记录后面的点,会隔过去一大堆点),但是还是错的,可能是思路就有问题。

后来查了正解发现是树DP(后来想了想确实跟树有关,一个是二叉再一个是跟基本01不同,它必须考虑从它的前一个也就是父节点转移来),还发现n要减1这件事情(处处都是出题人埋的坑),就开始照着树DP打,首先就是建树,博客正解都是说递归读入,就建了结构体写递归,一开始是打算写二叉树(因为走廊只分两叉),结果发现画有x个,二叉树对此就不适用了,就用回了树(实际应用还是应用了走廊分两叉这个特点),倒腾了一节多课倒腾出了输入。

然后就倒腾起了dfs更新f的值,还是参考了艺术馆,发现叶子节点的定义有些不一样,这道题叶子节点应该定义成有画的展厅,然后对这个展厅的画做最最最最最最最基本的01背包,就循环转移方程完全照搬只不过对“体积”的最大限制是对画DP时剩的时间。对画DP完全重开了一个一维数组01背包,然后就是对非叶节点也就是走廊的处理,这个比较好想到,就是把到这个走廊剩余的时间分给左右两个走廊去dfs取其中最大值,f的两维i和j表示了到第i个点还没有消耗走第i个点剩余时间j时所能获得的最大价值,因为是在递归(走到叶节点一层一层返回来),所以输出在祖先节点剩余所有时间时的f值。

剩下就是各种特判(因为样例一直不过调试发现必须要特判),加了各种特判以为可以A掉了,结果Runtime Error,就一直试着开大数组,然后就过了,不知道是哪个操作爆掉了数组下标越界了。

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 struct shu{
 5     int zi[5000],fu,jl=0,c;
 6     long long w;
 7 }a[5000];
 8 int n,t,x,js=1;
 9 long long f[5000][5000];
10 bool pd[5000];
11 void dr(int fa)
12 {
13     int t,x;  cin>>t>>x;  a[fa].c=t*2;
14     if(x!=0)
15     {
16         pd[fa]=1;
17         for(int i=1;i<=x;++i)
18         {
19             js++;  int c;  long long w;  cin>>w>>c;
20             a[fa].zi[++a[fa].jl]=js;
21             a[js].fu=fa;  a[js].c=c;  a[js].w=w;
22         }
23         return ;
24     }
25     js++;  a[fa].zi[++a[fa].jl]=js;  a[js].fu=fa;  dr(js);
26     js++;  a[fa].zi[++a[fa].jl]=js;  a[js].fu=fa;  dr(js);
27 }
28 long long  dfs(int fjd,int sj) 
29 {
30     if(f[fjd][sj]!=-1)  return  f[fjd][sj];
31     if(sj==0)  return  f[fjd][sj]=0;
32     if(sj<=a[fjd].c)  return  f[fjd][sj]=0;
33     if(pd[fjd]==1)
34     {
35         if(a[fjd].jl==1&&a[a[fjd].zi[1]].c>sj-a[fjd].c)
36             return f[fjd][sj]=0;
37         else
38         {
39             int sum=0,tot=0;
40             for(int i=1;i<=a[fjd].jl;++i)
41             {
42                 sum+=a[a[fjd].zi[i]].c;
43                 tot+=a[a[fjd].zi[i]].w;
44             }
45             if(sj-a[fjd].c>=sum)  return f[fjd][sj]=tot;
46             else
47             {
48                 long long dp[601];
49                 memset(dp,0,sizeof(dp));
50                 for(int i=1;i<=a[fjd].jl;++i)
51                 {
52                     int ls=a[fjd].zi[i];
53                     for(int j=sj-a[fjd].c;j>=a[ls].c;--j)
54                         dp[j]=max(dp[j],dp[j-a[ls].c]+a[ls].w);
55                 }
56                 return f[fjd][sj]=dp[sj-a[fjd].c];
57             }
58         }
59     }
60     f[fjd][sj]=0;
61     int sy=sj-a[fjd].c;
62     for(int i=0;i<=sy;++i)
63     {
64         long long zb=dfs(a[fjd].zi[1],i);
65         long long yb=dfs(a[fjd].zi[2],sy-i);
66         f[fjd][sj]=max(f[fjd][sj],zb+yb);
67     }
68     return f[fjd][sj];
69 }
70 int main()
71 {
72     cin>>n;  n-=1;  memset(f,-1,sizeof(f));
73     dr(js);
74     dfs(1,n);
75     cout<<f[1][n]<<endl;
76     return 0;
77 }
非正解且很慢

 

posted @ 2019-08-03 19:54  hzoi_X&R  阅读(334)  评论(0编辑  收藏  举报