cf(448c)-painting fence

这是一道面试题,同时是codeforces上的c类题目。
tags:divide and conquer,dp,greedy

解决思路

首先明确
  • 先需要明确每次只可能存在两种刷法,要么横着一笔,要么竖着一笔。
  • 竖着刷不会存在“断开”的问题,而横着刷会存在。
思考过程
step1

因为存在横向断开的问题,也就意味着可能需要分连续横向区间处理,那么首先应该想到用递归,每一层递归找到当前木材的最低高度,比这个高度更大的木材进入下一层递归,连续大于最低高度的木材为同一个递归。看题目给的数据范围,最多5000块木板,那么如果每一层递归仅仅只少1块木材,递归深度也不会超过5000,这对于gcc或者g++编译器来说是可以容忍的。

step2(建议看了代码再来看这一部分)

实在想不出有什么规律,那么我们假设所有木材全部竖着刷,然后与所有木材横着刷做比较,谁小谁就是结果。但是问题来了,横着刷存在断开的问题,不能一次性横向全部刷完,而且可能会存在在横着刷完后后面全部竖着刷可能次数更少。那就用递归,我们就找所有的木材中最小的高度,最小高度即为横向刷墙需要的次数,接着加上剩下墙刷的次数,就为横向刷墙的次数。然后把最小高度作为分界线,得到多个连续的更高高度的新墙,然后对这些子问题进行上述相同处理。

最终思路

最后的最小次数一定小于等于全部竖着刷墙,对于横着刷墙的情况,只有把0-最小高度刷完才可能比全部竖着刷墙更小(横向刷的范围不能更高,也不能更小,只能等于最小高度才可能取得最优解,至于为什么,也很好证明),所以我们需要讨论这种情况,这就有了分治的思想。刷完以后,我们把“基线”移到最小高度之上,这样就得到了多个连续的规模更小的新墙,这是与愿问题相同的子问题,我们需要求子问题的最优解愿问题的最优解就包含了子问题的最优解(最优子结构)当前的状态又是由横向刷和竖向刷两种情况中的最小值决定的。所以这道题就有了贪心、分治、动态规划思想在里面。

代码

#include <iostream>
#include <limits.h>
#include <algorithm>
using namespace std;
//max re-deep is 5000,is ok 
int dfs(int* a,int l,int r,int h)
{
    if(l == r) 
        return 1;
    int min_h = *min_element(a+l,a+r+1);
    int res = min_h - h;
    for(int i=l;i<=r;i++)
    {
        if(a[i] > min_h)
        {
            int j = i;
            while(j < r && a[j+1] > min_h ) j++;
            res += dfs(a,i,j,min_h);
            i = j;
        }
    }
    return min(res,r-l+1);
}

int main()
{
    int n;
    cin >> n;
    int arr[n];
    for(int i = 0;i<n;i++)
    {
        cin >> arr[i];
    }
    cout << dfs(arr,0,n-1,0);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值