zoukankan      html  css  js  c++  java
  • CF448C Painting Fence(分治)

    题意:有n块连着的木板,每个木板的高度为(h_i),你需要把这n块木板上色,每次上色你可以选择竖着刷完一块木板,或者横着刷一个高度单位的连续的木板(不能跳跃),问最少需要刷几次?

    分析:先只考虑贪心地横着涂:每一次尽可能地涂最长,且在此次横着涂的下方必定都是横着涂的,因为如果下面有竖着涂的,根据最优性,上一次竖着涂的时候肯定要把此次的也涂掉(这个自己想想很容易明白,对于一根木板,绝对不可能下面竖着涂,上面横着涂)

    所以对于一串连着的木板(h_1),(h_2)...(h_n),就必定是从下往上涂min{(h_1),(h_2)...(h_n)}次,这样以后(h_1),(h_2)...(h_n)就被分成了几串不连通的木板(子局面),说到这里,可以发现本题可以用分治解决,时间复杂度(O(N^2)).

    设work(l,r,now)表示对于[l,r]这一串连着的木板,已经从下往上涂了now格时的答案.

    设minh=min{(h_1),(h_2)...(h_n)},则work(l,r,now)=min(r-l+1,(sum work(u,v,minh))),其中[u,v]是分割出的一个子局面.至于为什么还要与r-l+1取min?因为如果横着涂比直接竖着涂要麻烦,那就不如直接每一根木板都竖着涂呗,一共有r-l+1根木板.

    最后注意一下边界情况l=r时,显然只有一根木板的话,那就直接竖着涂一次完事了.

    int n,h[5005];
    int work(int l,int r,int now){
        if(l==r)return 1;//边界情况
        int i,j,ans=0,minh=1e9;
        for(i=l;i<=r;i++)
    		if(h[i]<minh)minh=h[i];
    //找到[l,r]这一串木板中最短的木板
        ans+=minh-now;//记得减去之前已经涂了的now格
        for(i=l;i<=r;i++){//分割成子局面并处理
    		if(h[i]==minh)continue;
    		for(j=i;j<=r;j++)
    	    	if(h[j+1]==minh||j==r)break;
    		ans+=work(i,j,minh);
    		i=j+1;//刚开始忘记了这里
        }
        return min(r-l+1,ans);//与竖着涂取min
    }
    int main(){
        n=read();
        for(int i=1;i<=n;i++)h[i]=read();
        printf("%d
    ",work(1,n,0));
        return 0;
    }
    
    
  • 相关阅读:
    fedora如何删除某个包且不删除依赖它的相关包
    git分支切换时的时间戳问题
    [Centos] ERROR: Could not find useradd in chroot, maybe the install failed?
    linux通过python设置系统默认编码
    linux设置系统时间和时区
    python: "TypeError: 'type' object is not subscriptable"
    如何搭建http服务仓库
    [转载]RPM中SPEC常用路径以及宏变量
    spec文件写作规范
    GeoServer中利用SLD配图之矢量图层配图
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10359976.html
Copyright © 2011-2022 走看看