题目链接:http://codeforces.com/problemset/problem/448/C
题意:
有n个木板竖着插成一排栅栏,第i块木板高度为a[i]。
你现在要将栅栏上所有地方刷上油漆。
每次你可以选择竖着刷或横着刷,但必须保证一次刷的地方不能间断。
问你至少要刷几次才能刷满。
题解:
首先有一个贪心结论:
对于当前要刷的一片区域,令minn为这片区域的最小高度。
如果选择横着刷,则至少要将区域底部的minn层刷完。
如图,至少要将下面两层刷完:
然后考虑如何分治:
对于当前的这一片区域,将最下面的minn层去掉之后,原区域就变成了若干个小区域。
这样就转化成了若干个子问题。
所以当前区域的最小次数 = min( 只竖着刷的次数, 先横着刷minn次 + ∑ 子区域的最小次数 )
即:dfs(x,y) = min(y-x+1, minn + ∑ dfs(Li,Ri))
边界条件:x == y时,最多只用竖着刷一次。
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #define MAX_N 5005 5 #define INF 1000000000 6 7 using namespace std; 8 9 int n; 10 int a[MAX_N]; 11 12 int dfs(int x,int y) 13 { 14 if(x==y) return 1; 15 int minn=INF; 16 for(int i=x;i<=y;i++) minn=min(minn,a[i]); 17 for(int i=x;i<=y;i++) a[i]-=minn; 18 int sum=0; 19 int p=x; 20 for(int i=x;i<=y;i++) 21 { 22 if(a[i] && (i==y || !a[i+1])) sum+=dfs(p,i); 23 if(!a[i] && i<y && a[i+1]) p=i+1; 24 } 25 return min(sum+minn,y-x+1); 26 } 27 28 int main() 29 { 30 cin>>n; 31 for(int i=1;i<=n;i++) cin>>a[i]; 32 cout<<dfs(1,n)<<endl; 33 }