题解:
贪心+dp
30% N<=5 5!枚举一下
20% 高度没有的时候,高度花费就不存在了,将ci排序,
从小到大挨个跳。另外,20% 准备跳楼没有花费,那么跳
楼的高度一定是从小到大,或者是从大到小。所以按照hi从
小到大排序,那么跳楼一定是排序后连续的一段。枚举第一
栋楼从哪开始跳。对于100% (1)hi从小到大排序,最后高度
的花费一定是hend-hstart。那么start—end中间楼的高度就
不会造成影响,只需要将start—end中间的楼排序,取小的ci。
(2)现在跳在第i栋楼上,已经跳了j栋楼了的最小花费。
f[i][j]—>min{ f[k][j+1]+c[k]+abs{h[i]-h[k]} }
最后答案是枚举i,j。
代码:
暴力挂了20
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #define maxn 60 using namespace std; int n,t,ans,flag1,flag2,flag3; int vis[maxn]; struct Build{ int h,c; }b[maxn]; inline int read(){ int x=0,f=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0'; return x*f; } bool cmp1(Build a,Build b){ return a.c<b.c; } bool cmp2(Build a,Build b){ return a.h<b.h; } void dfs(int nxt,int now,int sum){ sum+=b[now].c; if(sum>t)return; ans=max(ans,nxt-1); for(int i=1;i<=n;i++){ if(vis[i]==0){ vis[i]=1; if(nxt==1){ dfs(nxt+1,i,sum); vis[i]=0; }else { dfs(nxt+1,i,sum+abs(b[now].h-b[i].h)); vis[i]=0; } } } return; } int main(){ freopen("meet.in","r",stdin); freopen("meet.out","w",stdout); n=read();flag1=true;flag2=true; for(int i=1;i<=n;i++)b[i].c=read(); for(int i=1;i<=n;i++)b[i].h=read(); t=read(); if(n<=5){ dfs(1,0,0); printf("%d\n",ans); fclose(stdin);fclose(stdout); return 0; } for(int i=2;i<=n;i++){ if(b[i].h!=b[i-1].h){ flag1=false;break; } } if(flag1){ int ret=0; sort(b+1,b+n+1,cmp1); for(int i=1;i<=n;i++){ if(t-b[i].c>0){ ret++;t-=b[i].c; } } printf("%d\n",ret); fclose(stdin);fclose(stdout); return 0; } for(int i=1;i<=n;i++){ if(b[i].c){ flag2=false;break; } } if(flag2){ sort(b+1,b+n+1,cmp2); for(int len=1;len<=n;len++){ flag3=false; for(int st=1;st+len-1<=n;st++){ int ed=st+len-1,pre=b[st].h,f=0; for(int i=st;i<=ed;i++){ f+=b[i].h-pre; pre=b[i].h; } if(f<=t)flag3=true,ans=max(ans,len); } if(flag3==false)break; } printf("%d\n",ans); fclose(stdin);fclose(stdout); return 0; } dfs(1,0,0); printf("%d\n",ans); fclose(stdin);fclose(stdout); return 0; }