【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;
}