当前位置: 代码迷 >> 综合 >> uva 3905 meteor(扫描线)(图形)
  详细解决方案

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

热度:47   发布时间:2024-01-09 02:44:14.0

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;elsereturn 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);elsenow--;}printf("%d\n",ans);}return 0;
}