CF1012C Solution

题目链接

题解

这是一道dp题。

状态:\(dp[i][j][k]\)表示前\(i\)座山上建\(j\)栋房子,第\(i\)座山上建/不建(\(k=1/0\))时的最小花费(\(k=1\)时不考虑\(a_{i+1}\ge a_i\)的花费)。

转移方程:

\[ dp[i][j][0]=min(dp[i-1][j][0],dp[i-1][j][1]+max(0,a[i]-a[i-1]+1)); \]

\(a_i\)不建房时,需要讨论\(a_{i-1}\)上是否有房子。如果没有直接转移,有的话需加上\(a_i\ge a_{i-1}\)的高度。因为也有\(a_i<a_{i-1}\)的可能,因此需要\(max(0,高度)\)

\[dp[i][j][1]=min(dp[i-2][j-1][0]+max(0,a[i-1]-a[i]+1),\\dp[i-2][j-1][1]+max(0,a[i-1]-min(a[i-2],a[i])+1)); \]

\(a_i\)建房时,\(a_{i-1}\)上只可没有房子,需要讨论\(a_{i-2}\)上有无房屋。如果没有需加上\(a_{i-1}\ge a_i\)的高度,如果有则\(a_{i-1}\)需同时低于\(a_i,a_{i-2}\),因此加上\(a_{i-1}\ge min(a_i,a_{i-2})\)的高度。

初始值:因为方程为取\(min\),初始值需赋极大值,而\(dp[i][0][0]\)也参与转移,需赋值\(0\)。此外状态\(dp[1][1][1]\)的花费也是\(0\),需要单独赋值。

答案:\(min(dp[n][i][0],dp[n][i][1]),\quad 1\le i\le \lfloor \frac{n+1}{2} \rfloor\)

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N=5010;
int a[N],dp[N][N][2];
int main()
{
	int n,st;
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	memset(dp,0x3f,sizeof(dp));
	for(int i=0;i<=n;i++) dp[i][0][0]=0;
	dp[1][1][1]=0; 
	for(int i=2;i<=n;i++)
	{
		for(int j=1;j<=(i+1)/2;j++)
		{
			dp[i][j][0]=min(dp[i-1][j][0],dp[i-1][j][1]+max(0,a[i]-a[i-1]+1));
			dp[i][j][1]=min(dp[i-2][j-1][0]+max(0,a[i-1]-a[i]+1),dp[i-2][j-1][1]+max(0,a[i-1]-min(a[i-2],a[i])+1));
		}
	}
	for(int i=1;i<=(n+1)/2;i++) printf("%d ",min(dp[n][i][0],dp[n][i][1]));
	return 0;
}
posted @ 2021-01-28 17:12  violet_holmes  阅读(67)  评论(0编辑  收藏  举报