HDU 1828 / POJ 1177 Picture 初涉扫描线

先贴个代码,题解明天补上,先去补读书笔记。。。

熬夜通宵补完了坑爹的读书笔记和社会实践报告,七千字额,呕心沥血的大作尴尬


题意:一个二维的平面内许多边平行于坐标轴的矩形相交,组成了比较复杂的多边行,求多边形的周长。


思路:一开始感觉数据范围这么大,肯定要用线段树优化的,结果作了半天的线段书,也没想出该怎么维护。。。。。。感觉弱爆了。。。。。。然后试了试不用线段树,结果31MS水过了。。


下面说一下自己对扫描线的理解:

扫描线给人的感觉就是在目标区域内有一条线按照一定的要求从一端扫到另一端,在扫描的过程内会碰到事先标记好的事件点,从而计算目标值。

对于这道题来说,目标值就是多边形的周长,事件点即为矩形的边。

以与Y轴平行的边为例。

扫描线的每条线段初始值为零,每次碰到左边则加一,碰到右边则减一,当标记从0变为1或从1变为0时,加上这一小段的值,当然还要注意去重边,如下面这组数据。

2

0  0  2  2

   2  1  3  3

显然与X轴平行的边也一样计算。


#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
#include <algorithm>

#define LL long long
#define Max(a,b) (a) > (b) ? (a) : (b)
#define Min(a,b) (a) < (b) ? (a) : (b)
#define EPS (1e-8)
#define Left (1)
#define Right (-1)

using namespace std;

struct P
{
    int x,y;
};

struct L
{
    P p1,p2;
    int mark;
}lx[10100],ly[10100];

struct S
{
    int cover,site;
}seg[10100];

int px[10010],py[10010];

int delsame(int *p,int n)
{
    if(n == 0)
        return 0;
    int top,i;
    for(i = 1,top = 1;i < n; ++i)
    {
        if(p[i] != p[i-1])
            p[top++] = p[i];
    }
    return top;
}

bool cmp(int a,int b)
{
    return a < b;
}

bool cmp_x(L l1,L l2)
{
    return l1.p1.x < l2.p1.x;
}

bool cmp_y(L l1,L l2)
{
    return l1.p1.y < l2.p1.y;
}

int BS(int *p,int m,int n)
{
    int s = 0,e = n - 1,mid;

    while(s < e)
    {
        mid = (s+e)>>1;
        if(p[mid] == m)
            return mid;
        if(p[mid] < m)
        {
            s = mid+1;
        }
        else
        {
            e = mid-1;
        }
    }
    mid = (s+e)>>1;
    if(p[mid] == m)
        return mid;
    return -1;
}

int main()
{
    int n;
    int t1,t2,ty,tx;
    P p1,p2;

    int i,j,s1,s2;

    int Perimeter;

    while(scanf("%d",&n) != EOF)
    {

        Perimeter = 0;

        t1 = t2 = tx = ty = 0 ;

        for(i = 0;i < n; ++i)
        {
            scanf("%d %d %d %d",&p1.x,&p1.y,&p2.x,&p2.y);

            lx[t1].p1 = p1;
            lx[t1].p2.x = p2.x;
            lx[t1].p2.y = p1.y;
            lx[t1].mark = Left;
            ++t1;
            lx[t1].p2 = p2;
            lx[t1].p1.x = p1.x;
            lx[t1].p1.y = p2.y;
            lx[t1].mark = Right;
            ++t1;

            ly[t2].p1 = p1;
            ly[t2].p2.x = p1.x;
            ly[t2].p2.y = p2.y;
            ly[t2].mark = Left;
            ++t2;
            ly[t2].p2 = p2;
            ly[t2].p1.x = p2.x;
            ly[t2].p1.y = p1.y;
            ly[t2].mark = Right;
            ++t2;

            px[tx++] = p1.x;
            px[tx++] = p2.x;
            py[ty++] = p1.y;
            py[ty++] = p2.y;
        }

        sort(px,px+ty,cmp);
        sort(py,py+ty,cmp);

        sort(lx,lx+t1,cmp_y);
        sort(ly,ly+t2,cmp_x);

        tx = delsame(px,tx);
        ty = delsame(py,ty);

        for(i = 0;i <= tx; ++i)
        {
            seg[i].cover = 0;
            seg[i].site = -10010;
        }

        for(i = 0;i < t1; ++i)
        {
            s1 = BS(px,lx[i].p1.x,tx);
            s2 = BS(px,lx[i].p2.x,tx);
            for(j = s1;j < s2; ++j)
            {

               if(seg[j].cover == 0)
               {
                   if(seg[j].site != lx[i].p1.y)
                   {
                       Perimeter += (px[j+1]-px[j]);
                   }
                   else
                   {
                       Perimeter -= (px[j+1]-px[j]);
                   }
                   seg[j].site = lx[i].p1.y;
                   seg[j].cover += lx[i].mark;
               }
               else
               {
                   seg[j].cover += lx[i].mark;
                   if(seg[j].cover == 0)
                   {
                       Perimeter += (px[j+1]-px[j]);
                       seg[j].site = lx[i].p1.y;
                   }
               }
            }
        }

        for(i = 0;i <= ty; ++i)
        {
            seg[i].cover = 0;
            seg[i].site = -10010;
        }

        for(i = 0;i < t2; ++i)
        {
            s1 = BS(py,ly[i].p1.y,ty);
            s2 = BS(py,ly[i].p2.y,ty);

            for(j = s1;j < s2; ++j)
            {
               if(seg[j].cover == 0)
               {
                   if(seg[j].site != ly[i].p1.x)
                   {
                       Perimeter += (py[j+1]-py[j]);
                   }
                   else
                   {
                       Perimeter -= (py[j+1]-py[j]);
                   }
                   seg[j].site = ly[i].p1.x;
                   seg[j].cover += ly[i].mark;
               }
               else
               {
                   seg[j].cover += ly[i].mark;
                   if(seg[j].cover == 0)
                   {
                       Perimeter += (py[j+1]-py[j]);
                       seg[j].site = ly[i].p1.x;
                   }
               }
            }
        }

        cout<<Perimeter<<endl;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值