UVALive - 3905 —— Meteor 流星

題目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=16454ios

1.對於每一顆流星而言,真正有意義的是它穿越矩形的有效時間,因此其實咱們須要獲得全部流星的有效時間this

2.這樣的話,原問題就轉化更加具體的:某個時刻最多同時穿過多少個時間段?spa

解決方案:code

  將每個時間區間,轉化爲兩個事件:開始事件和結束事件。咱們對全部事件按照時間排序,而後咱們有一個初始化爲0的tot變量計數,接着遍歷這個序列,遇到開始事件就+1,遇到結束時間就-1,而後在遍歷的過程當中保存最大的tot,這個最大值就是最後的解。blog

  最後要注意開始時間與結束事件重疊的狀況,即當某個時刻開始時間與結束事件重疊。若是是先+後-的話,那麼最大值會是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;
}
相關文章
相關標籤/搜索