问题描述
数轴上有n个闭区间D1,…,Dn。其中区间Di用一对整数[ai, bi]来描述,满足ai < bi。已知这些区间的长度之和至少有10000。所以,通过适当的移动这些区间,你总可以使得他们的“并”覆盖[0, 10000]——也就是说[0, 10000]这个区间内的每一个点都落于至少一个区间内。
你希望找一个移动方法,使得位移差最大的那个区间的位移量最小。
具体来说,假设你将Di移动到[ai+ci, bi+ci]这个位置。你希望使得maxi |ci| 最小。
输入格式
输入的第一行包含一个整数n,表示区间的数量。
接下来有n行,每行2个整数ai, bi,以一个空格分开,表示区间[ai, bi]。保证区间的长度之和至少是10000。
输出格式
输出一个数,表示答案。如果答案是整数,只输出整数部分。如果答案不是整数,输出时四舍五入保留一位小数。
样例输入
2
10 5010
4980 9980
样例输出
20
样例说明
第一个区间往左移动10;第二个区间往右移动20。
样例输入
4
0 4000
3000 5000
5001 8000
7000 10000
样例输出
0.5
样例说明
第2个区间往右移0.5;第3个区间往左移0.5即可。
数据规模和约定
对于30%的评测用例,1 ≤ n ≤ 10;
对于100%的评测用例,1 ≤ n ≤ 10000,0 ≤ ai < bi ≤ 10000。
//这里要确定的一件事是小数点最小的就是0.5,因为将1分为两部分肯定有一部分的小数大于0.5!!!
//这里要乘2倍,不然无法出现小数点
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
int N;
struct node
{
int left;
int right;
};
vector<node> reg;
bool cmp(node x,node y)
{
return x.right<y.right;
}
bool check(int x) //核心函数
{
int k = 0; //这里表示的是能覆盖的右边的极值点
vector<node> tmp(reg); //这里相当于复制一个与reg一摸一样的向量
while(1)
{
int Found=0; //表示查找是否有覆盖
for(int i = 0;i<tmp.size();i++)
{
node now = tmp[i];
int ta = now.left;
int tb = now.right;
if(ta-x<=k&&tb+x>=k)
{
Found = 1;
int len = tb-ta;
if(ta+x>=k) k+=len; //这里是覆盖的核心代码
else k=tb+x;
tmp.erase(tmp.begin()+i); //删除已经覆盖的区间
break;
}
}
if(!Found||k>=20000) break;
}
return k>=20000;
}
int main()
{
scanf("%d",&N);
int x,y;
for(int i = 1;i<=N;i++)
{
node t;
scanf("%d %d",&x,&y);
x<<=1;
y<<=1;
t.left =x;
t.right =y;
reg.push_back(t);
}
sort(reg.begin(),reg.end(),cmp); //从左往右查找则需要右结点进行排列
int l=0,r=20000,mid;
double ans=0; //可能不移动
while(l<=r) //注意二分条件包含等于
{
mid = (l+r)/2;
if(check(mid)) //mid 可以通过
{
r = mid-1;
ans = mid;
}
else
{
l = mid+1;
}
}
ans/=2.0;
cout<<ans<<endl;
return 0;
}