洛谷 CF1012C Hills (动态规划)

题目大意:有n个山丘 , 可以在山丘上建房子 , 建房子的要求是 : 该山丘的左右山丘严格的矮于该山丘 (如果有的话),你有一架挖掘机,每单位时间可以给一个山丘挖一个单位的高度,问你想要建造 1,2,3……n/2需要多少时间

输入:n个山丘的高度

输出:分别输出建造1,2,3……个房子的代价

 

分析:可以易得出两个性质

  1. 不可能连续两个山丘都建造房子

  2.如果该山丘建造房子就不可能挖该山丘(因为要保证该山丘严格的高于附近两个山丘,如果将该山丘高度降低,只能得到不会更优的结果)

那么我们可以讲每一个山丘 是否建造房子,用一维来表示,0代表不建造房子,1代表建造房子。

一共有n个山丘 假设要建造 m 座房子,那么我们用 i 来表示当前所处的山丘,用 j 来表示在此山丘以前已经建造了多少座房子

则f[i][j][1/0]

现在分析一下 第i座山丘不建造房子的情况

如果第i座山丘不建造房子 ,那么i - 1座可能建造也可能不建造,在两者中取一个较小值(注意i - 2座山丘,因为i 座山丘不建造,所以i - 2座山丘是否建造都不会对第i座山丘产生影响)

 

因此

f[i][j][0] = min{f[i-1][j][0],f[i-1][j][1] + max{0,a[i-1] - a[i] +1}}

 

(a[i]存储第i座山峰的高度,这里因为要保证严格的高于周围山峰,所以还要加上1)

 

然后分析第i座山峰建造房子的情况

如果第i座山峰建造房子,那么第i-1座只能不建造,但是这里需要注意的是,如果第i - 2 座山峰要建造房子的话,那么第 i - 1座山丘就不仅仅需要满足比 第 i 座山丘矮,还需要保证比i - 2矮,所以需要比较一下两者的较大值作为代价

因此

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

 下面是代码全貌

#include
using namespace std;

const int maxn = 5000+10;;
int n,a[maxn],dp[maxn],f[maxn][maxn][2];

int main(){
	memset(f,0x3f,sizeof(f));
	f[0][0][0] = 0;
	f[1][1][1] = 0;
	f[1][0][0] = 0;
	scanf("%d",&n);
	for(int i = 1;i <= n;++i)scanf("%d",&a[i]);
	dp[0] = 0x3fffffff;
	for(int i = 2;i <= n;++i){
		f[i][0][0] = f[i-1][0][0];
		for(int j = 1;j <= (i+1)/2;++j){
			f[i][j][1] = min(f[i-2][j-1][0]+max(0,a[i-1]-a[i]+1), f[i-2][j-1][1]+max(0,a[i-1]-min(a[i],a[i-2])+1));
			f[i][j][0] = min(f[i-1][j][0],f[i-1][j][1]+max(0,a[i]-a[i-1]+1));
		}
	}
	for(int i = 1;i <= (n + 1)/2;++i){
		printf("%d ",min(f[n][i][0],f[n][i][1]));
	}
	return 0;
}

 

你可能感兴趣的:(洛谷 CF1012C Hills (动态规划))