`
maybeiloveu
  • 浏览: 9022 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

POJ 1727-Advanced Causal Measurements (ACM)

阅读更多

http://acm.pku.edu.cn/JudgeOnline/problem?id=1727


      题目大意:给定一些点的坐标代表“事件”,每个“事件”可以有一些“因事件”,只要“因事件”的坐标落在给定不等式确定的范围之内即可。另给定数m表示至多有m个“因事件”。求对于给定的所有事件,它们的“因事件”中,最早发生的那一个事件的最迟发生时间(即最大的纵坐标)。


      为了方便,把题目中事件的记法(t, x)改为(x, y),t就相当于纵坐标。我这么想的,把那个不等式变个形,不难发现,对于一个事件(x, y)来说,能够导致它的“因事件”必然落在这样一个范围:过(x, y)分别做斜率为1和-1的直线,这两条直线下方的

区域就是“因事件”可能存在的范围。要求的纵坐标t,最大可能的值显然是所有给定的点中最小的纵坐标,最小可能的值根据题目的数据范围也能够定出。这个范围是有序的,t值越大越可能是最优的解。于是对这个区间进行二分,然后验证对于这个t,能否用不超过m个“因事件”来导致所有的点。

      这个验证的过程就比较简单了。例如要验证t,对于给定的所有事件点,对它们按照x坐标升序排序,x坐标相等的按y升序排,则可以计算出,对于要验证的纵坐标t,每个点的“因事件”在y=t这条直线上可能存在的坐标范围。遍历排序后的所有点,尽可能的计算出相邻两个点的“可能范围”的相交区间,若没有相交,则需要新增一个“因事件”点。这样算出来需要的总点数如果不超过m则记录答案,然后继续二分。

#include <cstdio>
#include <algorithm>

int n, m;

struct point {
    int x, y;
} p[100000];

bool cmp(const point &a, const point &b) {
    if (a.x != b.x)
        return a.x < b.x;
    return a.y < b.y;
}

bool check(int y) {
    int last_b, last_e, b, e, count;
    
    last_b = y - p[0].y + p[0].x;
    last_e = p[0].y - y + p[0].x;
    count = 1;

    for (int i = 1; i < n; i++) {
        b = y - p[i].y + p[i].x;
        e = p[i].y - y + p[i].x;
        if (last_e < b) {
            ++count;
            last_b = b;
            last_e = e;
        }
        else if (last_b <= b && b <= last_e && last_e <= e)
            last_b = b;
        else if (last_b <= b && e <= last_e) {
            last_b = b;
            last_e = e;
        }
        if (count > m)
            return false;
    }
    return true;
}

int main() {
    int cases, ymin, ymax;
    
    scanf("%d", &cases);
    for (int caseid = 1; caseid <= cases; caseid++) {
        scanf("%d%d", &n, &m);
        
        scanf("%d%d", &p[0].y, &p[0].x);
        ymax = p[0].y;
        
        for (int i = 1; i < n; i++) {
            scanf("%d%d", &p[i].y, &p[i].x);
            if (p[i].y < ymax)
                ymax = p[i].y;
        }
        
        std::sort(p, p + n, cmp);
        ymin = -2000010;
        
        int low = ymin, high = ymax, mid, ans;
        while (low <= high) {
            mid = (low + high) >> 1;
            if (check(mid)) {
                ans = mid;
                low = mid + 1;
            }
            else
                high = mid - 1;
        }
        
        printf("Case %d: %d\n", caseid, ans);
    }
  
    return 0;
}
分享到:
评论
1 楼 maybeiloveu 2010-06-20  
adfasdfasdfasdfasdf

相关推荐

Global site tag (gtag.js) - Google Analytics