代码长度限制 16 KB
时间限制 400 ms
内存限制 64 MB
题目描述
我的某室友学过素描,墙上有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。
个人思路
- 对1-m个木板分别进行计算,每多一块木板只需要找出这块木板的对面积整体面积进行优化最好的宽,所以便可看做是一个动态规划问题
- 于是可找出关键性公式dp[i][j]=min(dp[i][j],dp[i-k][j-1]+k*v[getmax(i-k+1,i)]);对每多一块木板时,该木板不同宽度中占用的最小面积进行计算。
- 下方代码中通过getmax算法来计算每两点之间需要的木板的最小值,这里也可以另写一个二维数组,先行计算各个值,然后在后面直接获取数组中的值即可,进一步优化一定程度的时间复杂度。
#include<bits/stdc++.h>
using namespace std;
vector<long long int> v;
long long int getmax(long long int a,long long int b)
{
long long int ans=a;
long long int max=v[a];
for(long long int i=a;i<=b;i++)
{
if(v[i]>max)
{
max=v[i];
ans=i;
}
}
return ans;
}
int main()
{
long long int n,m;
cin>>n>>m;
v.push_back(0);
long long int mins=0;
for(int i=0;i<n;i++)
{
long long int a;
cin>>a;
v.push_back(a);
mins+=a;
}
long long int dp[n+1][m+1];
long long int MAX=getmax(1,n);
for(long long int i=0;i<n+1;i++)
{
for(long long int j=0;j<m+1;j++)
{
if(i==0)
{
dp[i][j]=0;
}
else if(i==j)
{
dp[i][j]=mins;
}
else
dp[i][j]=v[MAX]*n;
}
}
for(long long int i=1;i<=n;i++)//一块木板
{
dp[i][1]=v[getmax(1,i)]*i;
}
for(long long int i=1;i<=n;i++)
{
for(long long int j=2;j<=m;j++)
{
if(j>i)
continue;
else
{
for(long long int k=1;k<=i-j+1;k++)//width
{
dp[i][j]=min(dp[i][j],dp[i-k][j-1]+k*v[getmax(i-k+1,i)]);
}
}
}
}
cout<<dp[n][m];;
}