看题目都看了半天,各种小条件,看了网上的思路才算把题目理解清楚了,主要是先按高度排序,再用线段树从下到上记录每块木板左右两边能跳到的id。然后从上到下作DP。中途能量不能小于1.
ACcode:
#include<stdio.h>
#include<iostream>
#include<algorithm>
using std::sort;
const int nsize=111111;
const int INF=100000000;
int *p[nsize<<1];
int lid[nsize],rid[nsize];
int trid[nsize<<2];
int dp[nsize];
struct Plank
{
int h,l,r,v;
}lk[nsize];
bool cmp1(int *a1,int *a2)
{
return *a1<*a2;
}
bool cmp2(Plank a1,Plank a2)
{
return a1.h<a2.h;
}
void build(int rt,int l,int r)
{
trid[rt]=0;
if (l==r) return ;
int m=(l+r)>>1;
build(rt<<1,l,m);
build(rt<<1|1,m+1,r);
}
int query(int rt,int l,int r,int k)
{
if (trid[rt]!=-1) return trid[rt];
int m=(l+r)>>1;
if (k<=m) return query(rt<<1,l,m,k);
else return query(rt<<1|1,m+1,r,k);
}
void PushDown(int rt)
{
if (trid[rt]!=-1)
{
trid[rt<<1]=trid[rt<<1|1]=trid[rt];
trid[rt]=-1;
}
}
void update(int rt,int l,int r,int L,int R,int id)
{
if (L<=l&&r<=R)
{
trid[rt]=id;
return ;
}
PushDown(rt);
int m=(l+r)>>1;
if (L<=m) update(rt<<1,l,m,L,R,id);
if (R>m) update(rt<<1|1,m+1,r,L,R,id);
}
int Max(int a1,int a2)
{
return a1>a2?a1:a2;
}
int main()
{
int n,i,m,cur;
while (scanf("%d",&n)!=EOF)
{
for (i=1;i<=n;i++)
{
scanf("%d %d %d %d",&lk[i].h,&lk[i].l,&lk[i].r,&lk[i].v);
dp[i-1]=-1;
p[i]=&lk[i].l;
p[n+i]=&lk[i].r;
}
sort(p+1,p+n*2+1,cmp1);
cur=*p[1]; *p[1]=1;
for (m=1,i=2;i<=n*2;i++)
{
if (*p[i]!=cur) m++,cur=*p[i];
*p[i]=m;
}
sort(lk+1,lk+n+1,cmp2);
build(1,1,m);
for (i=1;i<=n;i++)
{
lid[i]=query(1,1,m,lk[i].l);
rid[i]=query(1,1,m,lk[i].r);
update(1,1,m,lk[i].l,lk[i].r,i);
}
dp[n]=100+lk[n].v;
for (i=n;i>0;i--)
{
dp[lid[i]]=Max(dp[lid[i]],dp[i]+lk[lid[i]].v);
dp[rid[i]]=Max(dp[rid[i]],dp[i]+lk[rid[i]].v);
if (dp[lid[i]]<=0) dp[lid[i]]=-INF;
if (dp[rid[i]]<=0) dp[rid[i]]=-INF;
}
printf("%d\n",dp[0]>0?dp[0]:-1);
}
return 0;
}
这篇博客主要介绍了如何理解并解决HDU3016题目,首先按照木板高度排序,接着利用线段树记录每个木板左右两侧可跳跃的id。然后自顶向下应用动态规划进行求解,过程中确保能量始终不少于1。
1018

被折叠的 条评论
为什么被折叠?



