UVALive - 3905 —— Meteor 流星

题目: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;
}

 

posted on 2016-03-18 00:49  SuperChan  阅读(285)  评论(0编辑  收藏  举报

导航