Codeforces Round #145 (Div. 1, ACM-ICPC Rules) B. Fence

题意

    从左到右排列了 n( 1<=n<=200 )  个矩形,矩形的宽度是 1 cm,高度是 h[i](1<=h[i]<=200) cm。现在有两种颜料,每种颜料都是有限的,最多够涂 A cm^2 和 B cm^2 (0<=A,B<=4*10^4)的面积。定义一个和涂色的美观程度有关的估价函数: unattractiveness,如果涂好颜色之后相邻两个矩形的颜色不同,那么这个估价函数 unattractiveness 就得加上两个矩形相邻的面积,问怎么涂色才能使得 unattractiveness 最小。要求的是输出最小的 unattractiveness 值。

做法分析

    很明显的动态规划,第一想法是以 每次涂色 为阶段,状态就是:第 i 次涂色,还剩 a 个第一类颜料,和 b 个第二类颜料,转移方程也很好写,但是存在一个问题,这样定义状态的话,不仅 内存(n*A*B)不够,而且时间花费也是很大的(n*A*B),犯二了半天,最后反应过来了,要这样划分阶段:前 i 次涂色完成,这时候花费的第一种颜料为 a,花费的第二种颜料就是 前 i 个矩形的总面积 s[i]-a,状态就是和阶段的划分一样 f[i][a][flag] :前 i 次涂色花费的第一类颜料为 a,并且第 i 次涂色用的是 flag 这种颜料,这样时间和空间复杂度也能接受

AC通道

Codeforces Round #145 (Div. 1, ACM-ICPC Rules) B. Fence

参考代码

#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>

using namespace std;

const int INT_INF=0x3fffffff;
const int N=40010;

int h[205], s[205], c[205], f[205][N][2];

void init()
{
	memset(h, 0, sizeof(h));
	memset(s, 0, sizeof(s));
	memset(c, 0, sizeof(c));
	for(int i=0; i<205; i++)
		for(int j=0; j<N; j++)
			for(int k=0; k<2; k++)
				f[i][j][k]=INT_INF;
}

int main()
{
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);

	init();
	int n, a, b;
	scanf("%d%d%d", &n, &a, &b);
	for(int i=1; i<=n; i++)
	{
		scanf("%d", &h[i]);
		s[i]=s[i-1]+h[i];
		c[i]=min(h[i-1], h[i]);
	}
	f[0][0][0]=f[0][0][1]=0;
	for(int i=1; i<=n; i++)
		for(int j=0; j<=min(s[i], a); j++)
		{
			if(j>=h[i]) f[i][j][0]=min(f[i-1][j-h[i]][0], f[i-1][j-h[i]][1]+c[i]);
			if(s[i]-j<=b && j<=s[i]) f[i][j][1]=min(f[i-1][j][1], f[i-1][j][0]+c[i]);
		}
	int ans=INT_INF;
	for(int i=0; i<=a; i++)
		ans=min(ans, min(f[n][i][0], f[n][i][1]));
	if(ans==INT_INF) ans=-1;
	printf("%d\n", ans);
	return 0;
}


你可能感兴趣的:(Codeforces Round #145 (Div. 1, ACM-ICPC Rules) B. Fence)