题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=16454
1.对于每一颗流星而言,真正有意义的是它穿越矩形的有效时间,所以其实我们需要得到所有流星的有效时间
2.这样的话,原问题就转化更加具体的:某个时刻最多同时穿过多少个时间段?
解决方案:
将每一个时间区间,转化为两个事件:开始事件和结束事件。我们对所有事件按照时间排序,然后我们有一个初始化为0的tot变量计数,接着遍历这个序列,遇到开始事件就+1,遇到结束时间就-1,然后在遍历的过程中保存最大的tot,这个最大值就是最后的解。
最后要注意开始时间与结束事件重叠的情况,即当某个时刻开始时间与结束事件重叠。如果是先+后-的话,那么最大值会是2,相反就会使1。显然,在这里,后者才是正确的,因为由题意所有时间区间结尾开区间。
#include <cstdio> #include <iostream> #include <algorithm> #define INF 0x3f3f3f3f using namespace std; struct P { double t; int type; P(double t=0, int type=0) { this->t = t; this->type = type; } bool operator<(const P& p) const { if(t == p.t) return type > p.type; // 时间一样时,优先结束事件 return t < p.t; } } p[200005]; int tot; double l, r; // 得到某颗流星在某一维度上面经过矩形范围的区间,如果 左边界>右边界 说明 区间不存在 void f(int x, int w, int a) { if(a == 0) { if(x <= 0 || x >= w) { l = INF; r = 0; } } else if(a > 0){ l = max(l, -1.0*x/a); r = min(r, 1.0*(w-x)/a); } else { l = max(l, 1.0*(w-x)/a); r = min(r, -1.0*x/a); } } int main () { int T, w, h, n; scanf("%d", &T); while(T--) { scanf("%d%d%d", &w, &h, &n); int x, y, a, b; tot = 0; for(int i=0; i<n; i++) { scanf("%d%d%d%d", &x, &y, &a, &b); l = 0, r = INF; f(x, w, a); f(y, h, b); if(l<r) { p[tot++] = P(l, 0); p[tot++] = P(r, 1); } } sort(p, p+tot); int cur = 0, ans = 0; for(int i=0; i<tot; i++) { if(p[i].type == 0) { // 开始事件 +1 cur++; if(cur > ans) ans = cur; } else cur--; // 结束事件 -1 } printf("%d\n", ans); } return 0; }
LA - 3905 ——Meteor 流星
时间: 2024-12-21 06:37:48