Codeforces 448C Painting Fence(分治法)
题目链接: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 }