Codeforces-1013E:Hills【dp】

题意

  • 输入一串数字代表一串山坡的高度,如果当前山的高度比它两边的都要高,我们可以在上面盖一栋房子。可以用挖掘机挖山坡使其高度降低,一小时可以向下挖掉高度1(可以减到负数)。现在要分别找到想建i=1~n/2个房子,对每一个i输出需要挖掘的时间(n:5e3)

挺恶心的一道线性dp,这个用不着区间dp,因为当前状态完全可以从前面转移

对于第 i 个山坡,我们可以选择建或不建。

如果建,那么第 i - 1个山坡一定不能建,我们考虑一下建房子的代价。

  1.如果 i 比 i-1 高,代价显然是0

  2.如果 i 比 i-1 低或一样高,代价是 h[i-1]-h[i]+1

  我们可以用一种简洁的方式表示代价 :max(h[i-1]-h[i]+1, 0) 

如果不建,那么第 i-1 个山坡可以选择建或不建

  代价的讨论同上

我们用 dp[i][j][k]表示前 i 个山坡建 j 个房子,k 表示当前山坡建或不建,1为建,0为不建

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
using namespace std;
const int maxn = 5005;
int h[maxn], dp[maxn][maxn][2];
int max(int x,int y,int z){return max(z,max(x,y));}//我们一会要在三个数中取最大
int main(){
    int n; scanf("%d", &n);
    for(int i=1; i<=n; i++) scanf("%d", &h[i]);//读入山坡高
    memset(dp, 0x3f, sizeof(dp));//记得初始化dp
    dp[1][1][1] = dp[1][0][0] = 0;
    dp[2][1][1] = max(h[1]-h[2]+1, 0);
    dp[2][1][0] = max(h[2]-h[1]+1, 0);
    dp[2][0][0] = 0;
    //对于1 2我们可以直接得出
    for(int i=3; i<=n; i++){
        for(int j=0; j<i; j++){//枚举第i个山坡前建的房子数
            dp[i][j+1][1] = min(min(dp[i][j+1][1], dp[i-2][j][1]+max(h[i-1]-h[i]+1, h[i-1]-h[i-2]+1, 0)), dp[i-2][j][0]+max(h[i-1]-h[i]+1, 0));//我知道我写的很恶心
            //第 i 个山坡建房子,房子总数+1,第i-1个山坡已经确定不能建房子,我们讨论i-2
            //dp[i-2][j][1]+max(h[i-1]-h[i]+1, h[i-1]-h[i-2]+1, 0) 第i-2个山坡建房子,对于代价,我们需要让i-1同时比i-2和i低
            //dp[i-2][j][0]+max(h[i-1]-h[i]+1, 0) 第i-2个山坡不建房子,只要让i-1比i低就好了

            dp[i][j][0] = min(min(dp[i][j][0], dp[i-1][j][0]), dp[i-1][j][1]+max(h[i-2]-h[i-1]+1, h[i]-h[i-1]+1, 0));
            //第 i 个山坡不建房子,房子总数为 j,第i-1山坡可以建或不建
        }
    }
    for(int i=1; i<=(n+1)/2; i++) printf("%d ", min(dp[n][i][0], dp[n][i][1]));
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hzoi-poozhai/p/12686806.html
今日推荐