CF448C Painting Fence(来自洛谷)(贪心+分治)

洛谷地址:https://www.luogu.com.cn/problem/CF448C

题意:

有n块连着的木板,每个木板的高度为h_ihi,你需要把这n块木板上色,每次 上色你可以选择竖着刷完一块木板,或者横着刷一个高度单位的连续的木板(不能中 间空着的不能跳跃),问最少需要刷几次。

解析:

很明显,贪心策略是,优先横着刷每组最小值。

由于不能跳跃。

假设最低点位于中间md,那么以它横着刷,这个地方就会变成0,断点不能跳跃,所以区间分为了[L,md-1][md+1,r],自然就是分治的思想了。

几个细节:

为什么每次要和r-l+1取最小值呢,因为上述的贪心并不是最优的,因为我们的分治是以横着刷优先,假设有:

3  3  0  3,分治得到结果是4,但是直接竖着刷,结果是3。

递归出口:L==R的时候,是不能返回1的,如果此时的a[L]==0,它是不需要刷的,所以要和1取个最小值

#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=5e3+20;
const ll inf=0x3f3f3f3f3f3f3f3f;
int a[maxn];
int dfs(int l,int r)
{
//    cout<<l<<"--"<<r<<endl;
    if(l>r)
        return 0;  
    if(l==r)
        return min(a[l],1);
    int minn=inf,k;
    for(int i=l;i<=r;i++)
    {
        if(a[i]<minn)
        {
            minn=a[i];
            k=i;
        }
    }
    for(int i=l;i<=r;i++)
    {
        a[i]-=minn;
    }
    int c1=dfs(l,k-1),c2=dfs(k+1,r);
    return min(c2+c1+minn,r-l+1);
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    printf("%d
",dfs(1,n));
}
原文地址:https://www.cnblogs.com/liyexin/p/13503948.html