uva 3905 meteor(扫描线)(图形)

https://vjudge.net/problem/UVALive-3905

题目看着麻烦,其实写起来还好。

将每一个流星的运动分为X,Y方向上的运动,如果两个方向上都同时满足在范围之内,那么就是流星在方框内的时间范围。

扫描时间线的时候直接记录开始和结束的时间就可以了,每次不需要重新计算,而是维护结果就可以了,有点像点灯的题。实现的时候按照白书上的用结构体实现的,其实还可以开两个数组,分别储蓄开始和结束,sort之后类似于归并排序去处理。

#include <iostream>
#include<stdio.h>
#include<cstring>
#include<map>
#include<string.h>
#include<algorithm>
using namespace std;

struct Event
{
    int type;
    double time;
}event[100050*2];

void check(int x,int a,int w,double &L,double &R)
{
    if(a==0)
    {
        if(x<w&&x>0)    return;
        else    R=L-1;
    }
    else if(a>0)
    {
        L=max(L,-(double)x/a);
        R=min(R,(double)(w-x)/a);
    }
    else
    {
        a*=-1;
        L=max(L,(double)(x-w)/a);
        R=min(R,(double)x/a);
    }
}

bool cmp(Event a,Event b)
{
    if(a.time==b.time)
        return a.type>b.type;
    else
        return a.time<b.time;
}

int main()
{
    int cas;
    scanf("%d",&cas);
    while(cas--)
    {
        int w,h,n,x,y,a,b,cnt=0;

        scanf("%d%d%d",&w,&h,&n);
        for(int i=0;i<n;i++)
        {
            scanf("%d%d%d%d",&x,&y,&a,&b);
            double L=0,R=1e9;
            check(x,a,w,L,R);
            check(y,b,h,L,R);
            if(L<R)
            {
                event[cnt++]=(Event){0,L};
                event[cnt++]=(Event){1,R};
            }
        }
            sort(event,event+cnt,cmp);
            int ans=0,now=0;
            for(int i=0;i<cnt;i++)
            {
                if(!event[i].type)
                    ans=max(ans,++now);
                else
                    now--;
            }
            printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sadsummerholiday/article/details/82016393