poj1727 排序+二分搜索

来源:互联网 发布:泉州数据分析培训 编辑:程序博客网 时间:2024/06/06 03:08
/** * poj1727 排序+二分 * 类似题目的附图,在每个点以正负1为斜率作直线,两条直线以下的点就可以作为它的因果点 * 最大值就是所有点中最小的纵坐标;最小值,是最左的-1斜率直线与最右的+1斜率直线的交点 * 对符合范围的t进行二分定位,每一级t计算能覆盖所有输入点的最小点数count,如果count > m则向上查找,反之向下查找。最后输出的就是满足count <= m的最大t值 * 为了方便搜索,需要预先对所有点进行排序,排序的依据是,过该点的斜率为1的直线与x轴相交的点的x坐标,升序排列。排序之后,所有点是以与t=t0的左交点为准升序排列 * count的计算有点像之前做过的一个dp题,每次记录一个覆盖区间,如果新的点在t=t0的覆盖段与记录的覆盖区间没有交点,那么启用新的覆盖区间,并count++;否则用二者的交集更新覆盖区间 * 注意,我这道题用cin读就会超时,改用scanf就过了 */#include <iostream>#include <stdlib.h>#include <cstdio>using namespace std;const int MAX_NUM = 100002;struct point{    int x;    int t;} p[MAX_NUM];int n,m;//以与x轴交点的左边点为准,升序排列int cmp(const void* a,const void* b){    return ((*((point*)a)).x - (*((point*)a)).t) - ((*((point*)b)).x - (*((point*)b)).t);}//检查当前的t值下,至少需要的点数是否<=mbool check(int t){    int count = 1;    int last_left,last_right;    for(int i=1;i<=n;i++){        int left = t + p[i].x - p[i].t;        int right = p[i].x + p[i].t - t;        if(i == 1){            last_right = right;            last_left = left;            continue;        }        //如果左点与之前的区间不相交,那么自增count,维护一个新的区间        if(left > last_right){            count ++;            last_right = right;            last_left = left;        }        //如果当前点的区间完全在之前区间内部,区间是缩小了,以当前点区间为备选区间        else if(last_left <= left && last_right >= right){            last_right = right;            last_left = left;        }        //如果当前点的区间是与之前区间部分相交,那么只更新左点,以相交区间作为新的备选区间        else if(last_left <= left && left <= last_right && last_right <= right){            last_left = left;        }        if(count > m){            return false;        }    }    return true;}int main(){    int max_times;    cin >> max_times;    for(int times = 1;times <= max_times;++times){        int min_t = 99999999,search_top,search_bottom,leftest = 99999999,rightest = -99999999;        cin >> n >> m;        for(int i=1;i<=n;++i){            //cin >> p[i].t >> p[i].x;            scanf("%d%d",&p[i].t,&p[i].x);            if(min_t > p[i].t){                min_t = p[i].t;            }            leftest = (leftest > (p[i].t + p[i].x)) ? (p[i].t + p[i].x) : leftest;            rightest = (rightest < (p[i].x - p[i].t)) ? (p[i].x - p[i].t) : rightest;        }        search_top = min_t;        search_bottom = (rightest - leftest) / (-2);        //sort        qsort(p+1,n,sizeof(point),cmp);        //half deviding!!        int top = search_top, bottom = search_bottom, ans;        while(top >= bottom){            int search_t = (top + bottom) / 2;            //如果这一层的点数不够,则向上查找            if(check(search_t)){                ans = search_t;//最大的点数不够的点满足条件                bottom = search_t + 1;            }            //如果这一层的点数太多,则向下查找            else{                top = search_t - 1;            }        }        cout << "Case " << times << ": " << ans << endl;    }    return 0;}

0 0
原创粉丝点击