UVA 12170 Easy Climb 【单调队列优化DP+状态简化】

来源:互联网 发布:na.windows.app.23787 编辑:程序博客网 时间:2024/06/05 07:33

原题文档 

 uva12170  

题意:给你一些台阶的高度,使得相邻两个台阶之间的高度差不大于d(1<d<1e9),问至少需要增加或减少的高度和是多少。

分析:如果按照常规DP想总共有O(N*d)种状态,无解问题。找一找规律,当n=3时,第二个台阶只能修改max(h1,h3)-d,min(h1,h3)+d,h2.中的一种才能保证修改最小。然后可以推出每个台阶转移高度只能为hi+kd(-n<k<n)

状态就减少到O(n*n*n)种。然后推出状态转移方程dp[i][j]=|hi-j|+min(dp[i-1][k])(x[j]-d<=x[k]<=x[j]+d);看到这个式子。就可以想到用单调队列优化啦。(详见紫书P296)

附上代码

#include <stdio.h>#include <algorithm>#include <queue>#include <string.h>#include <math.h>#include <iostream>#include <math.h>#include <queue>#include <vector>using namespace std;typedef long long ll;const ll INF=((1LL)<<60);ll d,x[80100],h[111],dp[2][30010];int n;int main(){    int T_T;    scanf("%d",&T_T);    while(T_T--)    {        scanf("%d%lld",&n,&d);        for(int i=1;i<=n;i++)            scanf("%lld",&h[i]);        if(abs(h[1]-h[n])>(d*(ll)(n-1)))        {            printf("impossible\n");            continue;        }        int m=0;        for(int i=1;i<=n;i++)            for(ll j=-n;j<=n;j++)            x[m++]=h[i]+j*d;        sort(x,x+m);        m=unique(x,x+m)-x;        int t=1;        for(int i=0;i<m;i++)        {            dp[1][i]=INF;            if(x[i]==h[1])             dp[1][i]=0;        }        for(int i=2;i<=n;i++)        {            int k=0;            for(int j=0;j<m;j++)            {                while(k<m&&x[k]<(x[j]-d))k++;                while(k+1<m&&x[k+1]<=(x[j]+d)&&dp[t][k+1]<=dp[t][k])k++;                ll vv=dp[t][k];                if(vv==INF)                    dp[t^1][j]=INF;                else                    dp[t^1][j]=abs(h[i]-x[j])+vv;            }            t^=1;        }        ll ans=0;        for(int j=0;j<m;j++)        {            if(x[j]==h[n])            {                ans=dp[t][j];                break;            }        }        printf("%lld\n",ans);    }    return 0;}


 
原创粉丝点击