Codeforces 448C Painting Fence:分治

Leohh發表於2018-01-09

題目連結:http://codeforces.com/problemset/problem/448/C

題意:

  有n個木板豎著插成一排柵欄,第i塊木板高度為a[i]。

  你現在要將柵欄上所有地方刷上油漆。

  每次你可以選擇豎著刷或橫著刷,但必須保證一次刷的地方不能間斷。

  問你至少要刷幾次才能刷滿。

 

題解:

  首先有一個貪心結論:

    對於當前要刷的一片區域,令minn為這片區域的最小高度。

    如果選擇橫著刷,則至少要將區域底部的minn層刷完。

    如圖,至少要將下面兩層刷完:

    

  

  然後考慮如何分治:

    對於當前的這一片區域,將最下面的minn層去掉之後,原區域就變成了若干個小區域。

    這樣就轉化成了若干個子問題。

    所以當前區域的最小次數 = min( 只豎著刷的次數, 先橫著刷minn次 + ∑ 子區域的最小次數 )

    即:dfs(x,y) = min(y-x+1, minn + ∑ dfs(Li,Ri))

    邊界條件:x == y時,最多隻用豎著刷一次。

 

AC Code:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #define MAX_N 5005
 5 #define INF 1000000000
 6 
 7 using namespace std;
 8 
 9 int n;
10 int a[MAX_N];
11 
12 int dfs(int x,int y)
13 {
14     if(x==y) return 1;
15     int minn=INF;
16     for(int i=x;i<=y;i++) minn=min(minn,a[i]);
17     for(int i=x;i<=y;i++) a[i]-=minn;
18     int sum=0;
19     int p=x;
20     for(int i=x;i<=y;i++)
21     {
22         if(a[i] && (i==y || !a[i+1])) sum+=dfs(p,i);
23         if(!a[i] && i<y && a[i+1]) p=i+1;
24     }
25     return min(sum+minn,y-x+1);
26 }
27 
28 int main()
29 {
30     cin>>n;
31     for(int i=1;i<=n;i++) cin>>a[i];
32     cout<<dfs(1,n)<<endl;
33 }

 

相關文章