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("
");
return 0;
}