题目:Meteor
思路:对于每一颗流星,记录下它进入矩形和离开矩形的时间点(记为左端点和右端点),将这些时间点排序,遍历。遇到一个右端点cnt--,遇到一个左端点cnt++,cnt的最大值即为所求。当某一个左端点和一个右端点相同时,先处理右端点,因为在如果有一颗流星离开,一颗流星进入,那么无论何时,视野中都只可能存在这两颗流星中的一颗。如果先处理了进入而没有处理离开,此时就会错误的判断为这两颗流星同时出现在视野中了。
排序+扫描法
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <stack>
#include <queue>
#include <deque>
#include <set>
#include <cstring>
#include <map>
#include <cmath>
using namespace std;
#define db double
#define maxn 100000
int w,h;
int n;
struct Pair{
db x;
bool y;
Pair(){};
Pair(db xx,bool yy){
x=xx,y=yy;
}
bool operator < (const Pair& other) const { //先排右端点
return x<other.x||(x==other.x&&y>other.y);
}
};
void updata(int x,int a,int w,db& l,db& r){
if(a==0) {
if(x<=0||x>=w) r=l-1;
return ;
}
if(a>0){ // ->
l=max(-(db)x/a,l);
r=min((db)(w-x)/a,r);
} else { // <-
l=max((db)(w-x)/a,l);
r=min(-(db)x/a,r);
}
}
vector<Pair> vec;
int main() {
int T;
scanf("%d",&T);
while(T--) {
vec.clear();
scanf("%d%d",&w,&h);
scanf("%d",&n);
for(int i=1;i<=n;i++){
int x,y,a,b;
scanf("%d%d%d%d",&x,&y,&a,&b);
db l=0,r=(1<<30);
updata(x,a,w,l,r);
updata(y,b,h,l,r);
if(r>l){ //经过矩形内部
vec.push_back(Pair(l,false));
vec.push_back(Pair(r,true));
}
}
sort(vec.begin(),vec.end());
int ans=0,cnt=0;
for(int i=0;i<vec.size();i++){
if(vec[i].y) cnt--;
else cnt++;
ans=max(ans,cnt);
}
printf("%d\n",ans);
}
return 0;
}