1. 程式人生 > >Codeforces 448C Painting Fence(分治法)

Codeforces 448C Painting Fence(分治法)

劃分 .com 規劃 == sum tps codeforce nbsp 長度

題目鏈接:http://codeforces.com/contest/448/problem/C

題目大意:
n個1* a [ i ] 的木板,把他們立起來,變成每個木板寬為1長為 a [ i ] 的柵欄,現在要給柵欄刷漆,
刷子寬1,刷子可以刷任意長,每次只能橫著刷或者豎著刷,問最少需要刷幾次?
解題思路:
參考了這裏(https://blog.csdn.net/qq_24451605/article/details/48492573)
首先我們能夠想到,如果橫著刷,為了得到最優解,當前刷的位置的下面也必須橫著刷,然後對於每種情況都可以通過n次豎著刷得到整個黃色的柵欄。
所以我們采取分治的策略進行動態規劃,也就是對於每個狀態劃分為兩種情況討論,如果要刷橫向的話,

橫刷:將當前區間[l,r]的最矮的木板刷漆,然後再進入它的子區間即木板長度高於當前最矮木板的區間,然後求出所有子區間總花費就是橫著刷的花費。
豎刷:r-l+1
然後我們可以采取同樣的策略進行分治,知道墻只有一根柱子的時候,
可以直接通過一次豎著刷得到最優解,每次判斷決策時采取先橫著刷和直接豎著刷兩種方案中較小的方案。

代碼

 1 #include<bits/stdc++.h>
 2 #define lc(a) (a<<1)
 3 #define rc(a) (a<<1|1)
 4 #define MID(a,b) ((a+b)>>1)
 5
#define fin(name) freopen(name,"r",stdin) 6 #define fout(name) freopen(name,"w",stdout) 7 #define clr(arr,val) memset(arr,val,sizeof(arr)) 8 #define _for(i,start,end) for(int i=start;i<=end;i++) 9 #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); 10 using namespace std; 11 typedef long
long LL; 12 const int N=1e5+5; 13 const int INF=0x3f3f3f3f; 14 const double eps=1e-10; 15 16 int a[N]; 17 18 LL dfs(int l,int r,int h){ 19 if(l==r) return 1; 20 int hh=INF; 21 for(int i=l;i<=r;i++){ 22 hh=min(hh,a[i]); 23 } 24 LL sum=hh-h; 25 for(int i=l;i<=r;i++){ 26 if(a[i]==hh) continue; 27 int j=i; 28 while(a[j+1]>hh) j++; 29 sum+=dfs(i,j,hh); 30 i=j; 31 } 32 return min((LL)r-l+1,sum); 33 } 34 35 int main(){ 36 FAST_IO; 37 int n; 38 cin>>n; 39 for(int i=1;i<=n;i++){ 40 cin>>a[i]; 41 } 42 cout<<dfs(1,n,0)<<endl; 43 return 0; 44 }

Codeforces 448C Painting Fence(分治法)