Painting Fence
阿新 • • 發佈:2019-02-10
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() 9View Code{ 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 }
Painting Fence