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;
}
原文地址:https://www.cnblogs.com/ay27/p/2809324.html