codeforces 1013e E. Hills

链接: http://codeforces.com/contest/1013/problem/E

题意: 现在有n个山,高度为a ,如果想在一个山上建房子,那么必须要求该山严格高于两边的山,,你可以花费1的时间将一个山的高度降低1 ,问你建1 to (n+1)/2,分别所需要的时间。

思路: 很容易想到,长度为x ,那么我当前的x点建不建 只和他前一个位置状态有关。那么我就可以设 dp[ i ][ j ][ 0/1 ] 分别表示走到位置i建了j 个屋子,最后一个位置建不建, dp方程出来了,但是怎么转移呢,对于如果我当前位置不建房子的话,那么很容易,就直接看他的前一个状态就可以了。但是问题在于我当前位置建房子,那么肯定他的前一个状态是不建房子,那么问题来了,如果我只考虑他的前一个位置状态,那么就有 这样的一个问题  前两个位置状态为 10  并且 前两个的高度为  H i-1>=H i-2,并且如果 Hi <=Hi-1 那么如果只考虑i-1的状态肯定会出错,因为这样就多花费了时间。所以这里我们考虑前边两个位置的状态就可以了。那么如果我这个位置盖房子,那么 前一个状态肯定是  10  或者 00 呗。

代码:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int inf =0x3f3f3f3f;
const int N =5005;
int dp[5005][2505][2];
int a[N];
int n;

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    a[0]=a[n+1]=-inf;
    memset(dp,inf,sizeof(dp));
    dp[1][1][1]=0;
    dp[1][0][0]=0;
    dp[0][0][0]=0;
    int lim=(n+1)/2;

    for(int i=2;i<=n;i++){
        dp[i][0][0]=0;
        for(int j=1;j<=lim;j++){
            int x,y;
            x=max(a[i]+1-a[i-1],0);
            dp[i][j][0]=min(dp[i-1][j][0],dp[i-1][j][1]+x);
            x=max(a[i-1]+1-min(a[i],a[i-2]),0);
            y=max(a[i-1]+1-a[i],0);
            dp[i][j][1]=min(dp[i-2][j-1][1]+x,dp[i-2][j-1][0]+y);
            //cout<<"i "<<i<<" j "<<j<<endl;
            //cout<<dp[i][j][0]<<" "<<dp[i][j][1]<<endl;
        }
    }

    for(int i=1;i<=lim;i++){
        if(i==lim) printf("%d\n",min(dp[n][i][0],dp[n][i][1]) );
        else printf("%d ",min(dp[n][i][0],dp[n][i][1]));
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/yjt9299/article/details/82893906