【CF-1012 C. Hills】DP

Hills

题意

有n个土堆,第\(i\)个土堆高为\(a[i]\),现在要在土堆上面建造房子,只有当\(a_i>a_{i-1} and a_i >a _{i+1}\)

才可以把房子建到第\(i\)个土堆上,有一台推土机每小时可以推掉一个土堆一米,对于所有可能的\(k\),

输出建造至少\(k\)座房子需要最少的时间。

题解

参考博客

\(dp[i][j][0/1]\)表示在前\(i\)个土堆中,建造\(j\)坐房子,第\(i\)个土堆是否建造需要的最小时间。

如果第\(i\)个土堆,要建造房子:

只能从\(dp[i-1][j-1][0]\)转移来。那么要保证\(a_{i-1}<a_i\)

如果此时第\(i-2\)个土堆,也建造了房子,就要保证\(a_{i-1}<a_{i-2} ,a_{i-1}<a_i\),

此时\(dp[i][j][1]\)并没有考虑\(a_{i+1}\)的高度,但是\(dp[i][j][0]\)考虑了\(a_{i-1}\)的高度,如下。

\(i\)个土堆不建造房子:考虑第\(i-1\)是否建造房子,如果建造了要保证\(a_i<a_{i-1}\)

没有就直接转移。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=5e3+10;
const int inf=0x3f3f3f3f;
typedef long long ll;

int arr[N],dp[N][N][3];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&arr[i]);
    memset(dp,inf,sizeof(dp));
    dp[1][1][1]=dp[1][0][0]=dp[0][0][0]=0;
    for(int i=2;i<=n;i++)
    {
        for(int j=0;j<=(i+1)/2;j++)
        {
            dp[i][j][0]=min(dp[i-1][j][1]+max(0,arr[i]-arr[i-1]+1),
                            dp[i-1][j][0]);
            dp[i][j][1]=min(dp[i-2][j-1][0]+max(arr[i-1]-arr[i]+1,0),
                            dp[i-2][j-1][1]+max(0,arr[i-1]-min(arr[i-2],arr[i])+1));
        }
    }
    for(int i=1;i<=(n+1)/2;i++)
        printf("%d ",min(dp[n][i][0],dp[n][i][1]));
    printf("\n");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/valk3/p/12971195.html