洛谷地址: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)); }