和谐宿舍 (30 分)

代码长度限制 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. 对1-m个木板分别进行计算,每多一块木板只需要找出这块木板的对面积整体面积进行优化最好的宽,所以便可看做是一个动态规划问题
  2. 于是可找出关键性公式dp[i][j]=min(dp[i][j],dp[i-k][j-1]+k*v[getmax(i-k+1,i)]);对每多一块木板时,该木板不同宽度中占用的最小面积进行计算。
  3. 下方代码中通过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];;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值