USACO(Picture)转载

转载:http://www.nocow.cn/index.php/Translate:USACO/picture#SAMPLE_INPUT

描述

N(N<5000) 张矩形的海报,照片和其他同样形状的图片贴在墙上。它们的边都是垂直的或水平的。每个矩形可以部分或者全部覆盖其他矩形。所有的矩形组成的集合的轮廓称为周长。写一个程序计算周长。

图 1 是一个有 7 个矩形的例子:

picture-1.gif

图 1.一个 7 个矩形的集合

对应的轮廓为图 2 所示的所有线段的集合:

picture-2.gif

图 2. 矩形集合的轮廓

所有矩形的顶点坐标均为整数。所有的坐标都在 [-10000,10000] 的范围内,并且任何一个矩形面积都为整数。结果的值可能需要 32 位有符号整数表示。

格式

PROGRAM NAME: picture

INPUT FORMAT:

(file picture.in)

INPUT FORMAT 第1行: N,张贴在墙上的矩形的数目。 第 2..N+1行 接下来的N行中,每行都有两个点的坐标,分别是矩形的左下角坐标和右上角坐标。每一个坐标由 X 坐标和 Y 坐标组成。

OUTPUT FORMAT:

(file picture.out) 只有一行,为一个非负整数,表示输入数据中所有矩形集合的轮廓长度。

SAMPLE INPUT

7
-15 0 5 10
-5 8 20 25
15 -4 24 14
0 -6 16 4
2 15 10 22
30 10 36 20
34 0 40 16

SAMPLE OUTPUT

228

 

算法一

离散化

把所有矩形离散化(就是将整个平面分成许多“竖条”或“横条”,对其操作),每个矩形都由四条边组成,分为纵边和横边。对纵边和横边分别扫描一次,以横边为例:

  • 每个矩形的两条横边中,称下面的为始边,上面的为终边。
  • 把每条横边以纵坐标从小到大排序,如果纵坐标相同,则应把始边排到终边之前。
  • 依次枚举每条横边
    • 如果当前边为始边,则把这条边的横向的所有点j的层数增加1,即为level[j]++。如果层数由0变为了1,则这一点一定是边缘点,总周长ans++。
    • 如果当前边为终边,则把这条边的横向的所有点j的层数减少1,即为level[j]--。如果层数由1变为了0,则这一点一定是边缘点,总周长ans++。

同理按此方法扫描纵边,即可得到最后结果。

算法二

总思路:离散+线段树

首先是离散:

  • 显然,我们有2n条纵线和2n条横线。算法中,我们只考虑纵线,因为横线的做法同纵线的做法是相同的。离散就是将这2n条线段按照从左到右的顺序排序(也就是按照每条纵线的横坐标从小到大排序),这里需要注意一点:如果出现两个相同横坐标的纵线段,属于所在矩形左边的线段 要排在

属于所在矩形右边的线段 的左边。(这两个线段属于不同的矩形)。开始没注意到。。结果错了。。

然后是线段树:

  • 每个节点有6个属性:s,t,l,r,c,m,分别表示左边界、右边界、左子树、右子树、覆盖数、区间内

线段总长度。

  • 对于2n条纵线段,属于矩形左边的线段添加该线段到线段树(覆盖数+1),属于矩形右边的线段则从线

段树中删除该线段(覆盖数-1)。做添加、删除线段的同时,要维护m属性。规则如下:

    • 如果该段线段覆盖数(c)>0,则M即为线段长,
    • 如果覆盖数(c)=0,则M为 左儿子的M+右儿子的M。(如果本身是叶子就为0)
  • 每次操作线段后改变总长度(也可能不变),如果原来的长度为now,新的长度为new,如果new>now,则new-now算入答案ans。

源程序:

/*
ID: cmykrgb1
PROG: picture
LANG: C++
*/
//Written By CmYkRgB123
#include <iostream>
#include <fstream>
#include <cstdlib>
#define MAX 10001
using namespace std;
typedef struct
{
    int s,t,p;
    bool start;
}Line;
ifstream fi("picture.in");
ofstream fo("picture.out");
int N,ans=0;
int *level;
Line Lx[MAX],Ly[MAX];
inline int cmp(const void *a,const void *b)
{
    if (((Line*)a)->p==((Line*)b)->p)
    {
        if (((Line*)a)->start)
            return -1;
        else
            return 1;
    }
    return ((Line *)a)->p < ((Line *)b)->p ? -1 : 1;
}
void init()
{
    int i,x1,x2,y1,y2;
    fi >> N;
    for (i=1;i<=N;i++)
    {
        fi >> x1 >> y2 >> x2 >> y1;
        Lx[i*2-1].p=y1;
        Lx[i*2-1].s=x1;
        Lx[i*2-1].t=x2;
        Lx[i*2-1].start=false;
        Lx[i*2].p=y2;
        Lx[i*2].s=x1;
        Lx[i*2].t=x2;
        Lx[i*2].start=true;
        Ly[i*2-1].p=x1;
        Ly[i*2-1].s=y2;
        Ly[i*2-1].t=y1;
        Ly[i*2-1].start=true;
        Ly[i*2].p=x2;
        Ly[i*2].s=y2;
        Ly[i*2].t=y1;
        Ly[i*2].start=false;
    }
    N*=2;
    qsort(Lx+1,N,sizeof(Lx[0]),cmp);
    qsort(Ly+1,N,sizeof(Ly[0]),cmp);
    level=(int *)malloc(sizeof(int)*20002);
    level+=10000;
}
void Scan(Line *L)
{
    int i,j;
    for (i=-10000;i<=10000;i++)
        level[i]=0;
    for (i=1;i<=N;i++)
    {
        if (L[i].start)
        {
            for (j=L[i].s;j<L[i].t;j++)
            {
                level[j]++;
                if (level[j]==1)
                    ans++;
            }
        }
        else
        {
            for (j=L[i].s;j<L[i].t;j++)
            {
                level[j]--;
                if (level[j]==0)
                    ans++;
            }
        }
    }
}
void print()
{
    fo << ans << endl;
    fi.close();
    fo.close();
}
int main()
{
    init();
    Scan(Lx);
    Scan(Ly);
    print();
    return 0;
}

posted on 2009-04-13 09:09  Xredman  阅读(367)  评论(0编辑  收藏  举报

导航