• USACOShaping Regions


    来源:http://www.nocow.cn/index.php/Translate:USACO/rect1

    很明显灌水法是行不通的。

    什么是灌水法?就是把每一个矩形都标记一遍,最后扫描整个大矩阵,算法的时间复杂度是O(N^2),看数据规模就知道肯定死翘翘了。

    这题我选用了漂浮法,也称碰撞法。

    漂浮法在nocow上是这样描述的:

    漂浮法

    以逆序来进行放置,即n to 1。逆序的好处在于放置一个矩形后,俯视看到的就是最终俯视该矩形应该看到的。因为挡着它的矩形在之前已经放置好了,所以可直接统计,为递归创造了条件。每放一个矩形,可以想象成将其扔入一密度很大的海水底部,海分成了n层,然后矩形开始向上浮。在上浮过程中若碰撞到其他的矩形则断裂成几个小矩形,继续上浮,直到浮出水面。于是想到用个递归来模拟上浮过程。

    下面是我的个人见解:

    我们先考虑简单的情况:

             情况1                               情况2                                    情况3                                   情况4

    1  2  3  4

    这是最简单的4种遮挡情况,而复杂的遮挡情况总可以通过矩阵分割得到上面几种情况,举个例子:

    5

    对于这样的遮挡,我们可以这样分割:

    5

    把这种情况看成是情况1进行处理,先处理蓝色的部分,对于右边部分进行递归,按照情况3进行处理,其他所有的遮挡情况均可类似分割。

    值得注意的是以下的遮挡情况:

    6

    我们需要进行如下切割:

    6

    这个需要对切割时的判断条件进行精确的描述。

    到此,我们已经找到了处理遮挡的一般方法,下面进行总结:

    1.我们可以从最底部,也可以从最顶部开始处理每个矩阵,这里采用从最底部的矩阵开始处理;

    2.枚举每一个矩阵,与当前处理的矩阵进行遮挡处理,这个遮挡处理的递归终止条件是分割的小矩阵已处于最顶部;

    3.统计每个颜色的面积。

    给出核心代码:

    void cover(int lx,int ly,int ux,int uy,int col,int k)  //(lx,ly)左下角,(ux,uy)右上角,下面的数组类似
    {
        while (k<=n && (llx[k]>=ux || urx[k]<=lx || lly[k]>=uy || ury[k]<=ly))
            k++;
        if (k>n) { S[col]+=((ux-lx)*(uy-ly)); return; }
        if (lx<=llx[k]) { cover(lx,ly,llx[k],uy,col,k+1); lx=llx[k]; }  //情况1
        if (ly<=lly[k]) { cover(lx,ly,ux,lly[k],col,k+1); ly=lly[k]; }  //情况3
        if (ux>=urx[k]) { cover(urx[k],ly,ux,uy,col,k+1); ux=urx[k]; }  //情况2
        if (uy>=ury[k]) { cover(lx,ury[k],ux,uy,col,k+1); uy=ury[k]; }  //情况4
    }

    其实对于每个情况都有几种判断方法,比如情况1,可以写(lx<=llx[k]),也可以写成(ux<=urx[k]),还有(llx[k]<=ux),但是后面的两种判断并不准确,比如说(llx[k]<=ux)也可以用来表示情况2,所以这里的几个条件一定要重视。

    更具体的代码:

    /*
    ID:ay27272
    PROG:rect1
    LANG:C++
    */
    
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    #define NN 1005
    
    int llx[NN],lly[NN],urx[NN],ury[NN],color[NN];
    
    int S[NN];
    int n;
    
    void cover(int lx,int ly,int ux,int uy,int col,int k)
    {
        while (k<=n && (llx[k]>=ux || urx[k]<=lx || lly[k]>=uy || ury[k]<=ly))
            k++;
        if (k>n) { S[col]+=((ux-lx)*(uy-ly)); return; }
        if (lx<=llx[k]) { cover(lx,ly,llx[k],uy,col,k+1); lx=llx[k]; }
        if (ly<=lly[k]) { cover(lx,ly,ux,lly[k],col,k+1); ly=lly[k]; }
        if (ux>=urx[k]) { cover(urx[k],ly,ux,uy,col,k+1); ux=urx[k]; }
        if (uy>=ury[k]) { cover(lx,ury[k],ux,uy,col,k+1); uy=ury[k]; }
    }
    
    int main()
    {
        freopen("rect1.in","r",stdin);
        freopen("rect1.out","w",stdout);
        int X,Y,max_color=0;
        cin>>X>>Y>>n;
        for (int i=1;i<=n;i++)
        {
            scanf("%d%d%d%d%d",&llx[i],&lly[i],&urx[i],&ury[i],&color[i]);
            if (color[i]>max_color) max_color=color[i];
        }
    
        memset(S,0,sizeof(S));
    
        for (int i=1;i<=n;i++)
            cover(llx[i],lly[i],urx[i],ury[i],color[i],i+1);
    
        S[1]=X*Y;
        for (int i=2;i<=max_color;i++)
            S[1]-=S[i];
        for (int i=1;i<=max_color;i++)
            if (S[i]) cout<<i<<" "<<S[i]<<endl;
        return 0;
    }
  • 相关阅读:
    ConcurrentHashMap源码分析
    HashMap源码与相关面试题
    字符串学习笔记(三)---- StringBuilder
    字符串学习笔记(二)---- StringBuffer
    Vue一些基本操作技巧
    PHP代码及命名规范
    Js返回顶部的方法
    linux下镜像网站的几种方法
    单例模式示例
    工厂模式和IOC练习
  • 原文地址:https://www.cnblogs.com/ay27/p/2809324.html
Copyright © 2020-2023  润新知