UVALive 3905-Meteor-扫描线算法

来源:互联网 发布:电子音乐合成器软件 编辑:程序博客网 时间:2024/05/17 03:43

http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=16454

题意 

给一个(0,0)到(w,h)的矩形,

给n个流星位置(x,y),以及他们往的方向(a,b),流星的轨迹会是(x,y)-》(a,b)射线

X=x+a*t

Y=y+b*t

求某一时刻 矩形内星星最多的个数

那么显然我们要求的是流星的射线轨迹在矩形内的时间,也就是把上面两个公式的X,Y代入0,w(h)解得一个时间范围【L,R】,显然R<L舍弃,

然后我们求得所有的【L,R】(开区间,因为题目说,在边缘的星星不合法)


我们把这些开区间看成一条条线段

我们要找的答案就是 实数轴上 被这些线段重叠次数最多的 点


我们把每个区间看成一个事件, 把左端点看成事件1,右端点为事件2。

按端点坐标排序,端点坐标相同,右端点优先(如果左端点有限,由于是开区间,计算过程会比实际答案大)

然后遍历,遇到事件1,计数器++,else 计数器 --

最后输出maxx


(注意,时间的区间范围,的R最大值是 w-x或x)

#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <algorithm>#include <queue>#include <map>#include <set>#include <vector>#include <iostream>using namespace std;const double pi=acos(-1.0);double eps=0.000001; double max(double a,double b){return a>b?a:b;}double min(double a,double b){return a<b?a:b;}struct node{double x;int type;};node tm[200005];void update(int x,int a,int w,double&L,double &R){if (a==0){if (x<=0||x>=w) R=L-1; // 无解}else if (a>0){R=min(R,1.0*(w-x)/a);L=max(L,-x*1.0/a);}else{L=max(L,1.0*(w-x)/a);R=min(R,-x*1.0/a);}}bool cmp(node a,node b){if (fabs(a.x-b.x)>eps)return a.x<b.x;elsereturn a.type>b.type;}int main(){int i,t;  cin>>t;while(t--){int x,y,a,b;int ok=0;int w,h,n;cin>>w>>h>>n;for (i=1;i<=n;i++){double L=0,R=3e5+5;//注意R的最大值是(w-x)或x,1e5+2e5=3e5scanf("%d%d%d%d",&x,&y,&a,&b);update(x,a,w,L,R); update(y,b,h,L,R);// 0<x+a*t<w// 0<y+b*t<hif (R<=L) continue; tm[++ok].x=L;tm[ok].type=1;tm[++ok].x=R;tm[ok].type=2;}sort(tm+1,tm+1+ok,cmp);int maxx=0;int cun=0;for (i=1;i<=ok;i++){if (tm[i].type==1)cun++;elsecun--;if (cun>maxx) maxx=cun;}printf("%d\n",maxx);}   return 0;} 



0 0
原创粉丝点击