UVA1398 Meteor
扫描线的裸题,但是其中的几何知识倒是挺有意思,就是判断一个射线进入目标矩阵的进入时间和离开的时间:
假设源点的位置是(x,y),移动的速度是(a,b),矩阵的左下角是(0,0),右上角是(w,h)
一:最朴素的思路:
由几何知识可知,这条射线过(x+at,y+bt),首先有几种情况是可以排除的:
1、a>0 && x>w
2、a<0 && x<0
3、b>0 && y>h
4、b<0 && y<0
因为这几种情况该射线是不穿过矩形的(但是不仅仅局限于这四种)剩下的就是对a的正负,b的正负进行分类讨论的,工作量极其的大(写了一半就放弃了,如果没有别的思路千万不要忘记a和b等于零的情况!)
二:蓝书上给的思路:
我们把横方向和纵方向分开来看
L是进入时间,R是离开时间,初始化为L = 0,R = INF;
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){
L = max(L,-1.0*x/a);
R = min(R,1.0*(w-x)/a);
}
else if(a<0){
L = max(L,1.0*(w-x)/a);
R = min(R,-1.0*x/a);
}
}
在这里我们就以横方向为例,他在X轴上的位置是x,在x轴上的速度是a(有正负),矩形在x轴的范围是(0,w),这样来看是不是就很容易就求出在X轴上的进入和离开时间了呀,然后同理把Y轴的信息带入我们就能得到答案了,然后我们来分析是怎样得到该方向上的进出时间的:
①如果速度a==0,说明在该方向上该点不动,如果在该条件下流星的横坐标在矩形的范围之外,所以我们判定流星不经过矩形,所以令R = L-1;(后面判断流星是否经过矩形的判断依据)
②如果速度大于0,说明流星是从左往右运动,那么流星进入矩形的时间就是 (x-0)/ a,离开矩形的时间就是(w-x)/ a,这里有一个小点,不过很容易就想出来,在这里就不过多赘述了。
③如果速度小于0,说明流星是从右往左运动,那么流星进入矩形的时间就是(x-w)/ (-a),离开矩形的时间就是x / (-a) 。
然后我们再对Y轴方形进行同样的操作处理,然后就能得到一个整体进入矩形的时间和离开矩形的时间,如果进入的时间小于离开的时间,说明这个流星在视野里面出现过,所以我们就把这个流星的信息进行存储。
扫描线的知识在这里就不过多说明了,唯一一点就是先统计离开的,再统计进入的就好了,完整代码如下:
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 1e5+10;
struct edge{
double t;
int state;
}Time[maxn<<1];
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){
L = max(L,-1.0*x/a);
R = min(R,1.0*(w-x)/a);
}
else if(a<0){
L = max(L,1.0*(w-x)/a);
R = min(R,-1.0*x/a);
}
}
bool cmp(edge a,edge b){
if(a.t==b.t) return a.state > b.state;
else return a.t < b.t;
}
int main(){
int T;
cin >> T;
while(T--){
int w,h,n;
cin >> w >> h >> n;
int cnt = 0;
int x,y,a,b;
for(int i=0;i<n;i++){
cin >> x >> y >> a >> b;
double L,R;
L = 0;
R = 0x7f7f7f7f;
update(x,a,w,L,R);
update(y,b,h,L,R);
if(L<R){
Time[++cnt].state = 0;
Time[cnt].t = L;
Time[++cnt].state = 1;
Time[cnt].t = R;
}
}
sort(Time+1,Time+cnt+1,cmp);
long long ans = 0;
long long now = 0;
for(int i=1;i<=cnt;i++){
// cout << Time[i].t << ' ' << Time[i].state << endl;
if(Time[i].state==0) now++;
else now--;
ans = max(ans,now);
}
cout << ans << endl;
}
return 0;
}