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; }