题意
从左到右排列了 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通道
参考代码
#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;
}