UVA1398 Meteor(几何+扫描线)

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值