LA3905 meteor流星

题目大意
给定一个矩形照相机,还有哪个流星的起始位置和速度,求能可以照到最多流星的时刻。在边框上的不计入总数。
分析
不难发现流星的轨迹没有任何意义,有意义的只是流星在照相机内部出现的时间段,我们可以把每一个流星经过的时间转化为一个区间,这样的话问题就转化位在最多区间覆盖的点。即,求求出一个数t,使得包含的区间数最多。
在这里插入图片描述

我们把"扫描线碰上一个左端点"和“扫描线遇到一个右端点作为”作为一个事件,扫描并且维护,,每当遇到一个左端点,计数器加一,遇到一个右端点计数器进行减一,在这里我们还需要判断扫描线喷上的端点是右端点还是左端点,尤其注意做右端点重合的情况

#include<iostream>
#include<algorithm>
#include<cstdio>
#define maxn 100000+10
using namespace std;

struct event {
	double limt;
	int type;
	bool operator <(const event &a) const
	{
		return limt < a.limt||(limt==a.limt&&type>a.type);
	}
}events[maxn * 2];
void  update(int x, int v, int w, double &l, double &r)
{
	//cout <<x<<"-"<< w << endl;
	if (v == 0)
	{
		if (x <= 0 || x >= w) {
			//cout << "成功生成" << x << endl;
			r = l - 1;
		}
	}
	else if (v > 0)
	{
		l = max(l, -(double)x / v);
		r = min(r, (double)(w - x) / v);
	}
	else
	{
		r = min(r, -(double)(x) / v);
		l = max(l, (double)(w - x) / v);
	}
}
int main()
{
	int w, h, e;
	int t;
	cin >> t;
	while (t--)
	{
		int n;
		cin >> w >> h>>n;
		e = 0;
		int x, y, vx, vy;
		for (int i = 0; i < n; i++)
		{
			cin >> x >> y >> vx >> vy;
			double l = 0, r = 1e9;
			update(x, vx, w, l, r);
			update(y, vy, h, l, r);
			if (r > l)
			{
				events[e++] = event({ l, 0 });
				events[e++] = event({ r, 1 });
				//cout <<x<<"-"<<y<<"  "<< l << "-" << r << endl;
			}
		}
		sort(events, events + e);
		int cnt = 0, ans = 0;
		for (int i = 0; i < e; i++)
			if (events[i].type == 0)
				ans = max(ans, ++cnt);
			else cnt--;
		cout << ans << endl;
	}
	return 0;
}

其实关于蓝书中代码有一点疑问,既然是开区间,为什么扫描至端点就加一减一, 似乎懂了,扫描线看似是端点处加一减一实际上端点之后的状态,而且排序中对于相同值的左右端点,明显右端点的级别高,首先减一,如果是扫描闭区间的话,则相反,对于相同值的左右端点,左端点的优先级最高,先加一

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值