1. 程式人生 > >Painting Fence

Painting Fence

getch using show 文件 new blank har pan 註意

  傳送門

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

Painting Fence