资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
我的某室友学过素描,墙上有n张他的作品。这些作品都是宽度为1,高度不定的矩形,从左到右排成一排,且底边在同一水平线上。
宿舍评比就要来了,为了及格,我们决定买不多于m块的矩形木板,把这些作品和谐掉。要求木板也从左到右排成一排,且底边与作品的底边在同一水平线上。
在能够把所有作品和谐掉的前提下,我们希望这些木板的面积和最小,问最小面积和。
输入格式
第一行两个数n和m,表示作品数和木板数;
第二行n个数Hi,表示从左到右第i个作品的高度。
输出格式
一行一个数ans,表示答案。
样例输入
5 2
4 2 3 5 4
样例输出
22
数据规模和约定
对于30%的数据:1<=n,m<=10;
对于100%的数据:1<=n,m<=100,1<=Hi<=10000。
Code
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int dp[N][N];//用i块木板遮住前j幅画的面积最小值 所求即dp[m][n]
int maxij[N][N];//记录i~j幅画最大的高度值
int h[N];
int main()
{
int n, m;
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &h[i]);
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
maxij[i][j] = max(maxij[i][j - 1], h[j]);//找出i~j幅画的最大高度
for (int i = 1; i <= n; i++)//当只用一块板时,1~i的画所用面积便是1~i中最大画高度*1~i区间长度
dp[1][i] = maxij[1][i] * i;
for (int i = 2; i <= m; i++)//枚举板子数
for (int j = 1; j <= n; j++)//枚举画数
if (j <= i)//当板数仍然大于画数,每个画用一个板子面积最小
for (int k = 1; k <= j; k++)//前j个板子都只用一个高度为本身h[j]的板子
dp[i][j] += h[k];
else {//当板数小于画数,即j>i。那么第j幅画就要和其前面的某些画共用板子,具体和前几幅画共用一块板子通过循环判断
for (int k = 1; j - k+1 >= i; k++)//假设第j幅画和其前k幅画共用一块板子,
//共用板子的左端画数j-k+1需>=i。即对于最左端画也是要共用板子
if (k == 1)
dp[i][j] = dp[i - 1][j - k] + maxij[j - k + 1][j] * k;//第一次赋值,否则直接比较全为0
else//和第j幅画公用的画的最左端的左边的画数即为j-k
dp[i][j] = min((dp[i - 1][j - k] + maxij[j - k + 1][j] * k), dp[i][j]);
}
printf("%d", dp[m][n]);
return 0;
}