Painting Fence

  传送门

Description
zed 最近总是受到 Farmer 的困扰,因此他在自家的门前插了一排栅栏以防农气的入侵。栅栏由 N 个竖条栅栏横向组成,每个竖条栅栏宽度为 1。
过了一段时间,zed 觉得栅栏非常不美观。因此,他想给栅栏涂上颜色。问题是,zed的刷子宽度只有 1,也就是说,一次只能将连续的一排或一列格子涂上颜色(长度任意)
zed 想用最少的次数把栅栏全部涂上颜色(注意,一个格子不能重复涂色)。但是 zed 现在没时间,所以这个问题就交给你了。


Input
第一行为一个整数 N,代表栅栏的宽度。
第二行为 N 个整数 h 1 ~ h n ,代表从左向右每个竖条栅栏的高度。


Output
输出文件有且仅有一行,一个整数 ans,代表将整个栅栏涂色所用最少次数。

Solution:

"  考虑横着涂一次的情况,那么有两个显而易见的事实。
  1、 这次涂色长度必须尽可能大。
  2、 在这次涂色区域的下方,必定都是横着涂的。
  所以,对于一串栅栏h1,h2,...,hn,如果要横着涂,就必定要从底向上涂min⁡{h1,h2,...,hn}次。

  这样以后,h1,h2,...,hn就会分成若干不连通的子局面。
  那么显然可以设计一个分治的算法,时间复杂度为O(N2):
  令Solve(l, r, h)代表[l, r]这段栅栏,已经从下向上涂了h格的答案。
  令 h′=min⁡{h1,h2,...,hn},那么:
  Solve(l,r,h)=⁡min{⁡r−l+1,∑solve(u,v, h ′ )⁡|⁡[u, v]为分割出的子局面⁡⁡}
  边界情况:l=r时,答案显然为1。  "

CODE:

 1 #include<iostream>
 2 #include<cstdio>
 3 #define R register
 4 #define go(i,a,b) for(R int i=a;i<=b;i++)
 5 #define M 5000+1
 6 #define inf 2100000000
 7 using namespace std;
 8 int read()
 9 {
10     int x=0,y=1;;char c=getchar();
11     while(c<'0'||c>'9') {if(c=='-') y=-1;c=getchar();}
12     while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}  
13     return x*y;
14 }
15 int n,h[M];
16 int solve(int l,int r,int h1)
17 {
18     if(l>r) return 0;
19     int minh=inf,ans,l1=l;
20     go(i,l,r) minh=min(minh,h[i]);
21     ans=minh-h1;
22     go(i,l,r)
23         if(h[i]==minh) ans+=solve(l1,i-1,minh),l1=i+1;
24     ans+=solve(l1,r,minh);
25     return min(ans,r-l+1);
26 }
27 int main()
28 {
29     n=read();go(i,1,n) h[i]=read();
30     printf("%d",solve(1,n,0));
31     return 0;
32 }
View Code

猜你喜欢

转载自www.cnblogs.com/forward777/p/10359953.html