[洛谷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个。
注意题目要求你在不被逮捕的情况下得到最多的价值
样例的输入对应于下图
一开始打纯暴力,看出来了是背包,打了纯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 }非正解且很慢
标签:洛谷,sj,int,js,fa,偷天换日,走廊,fjd,P3360 来源: https://www.cnblogs.com/hzjuruo/p/11296052.html