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 }

 

posted @ 2018-11-01 20:33  Yeader  阅读(717)  评论(0编辑  收藏  举报