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;
else
return 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=3e5
scanf("%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<h
if (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++;
else
cun--;
if (cun>maxx) maxx=cun;
}
printf("%d\n",maxx);
}
return 0;
}