您的位置:首页 > 其它

poj1727 排序+二分搜索

2014-03-12 08:19 232 查看
/**
* 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值下,至少需要的点数是否<=m
bool 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: