题目描述#
n个在X轴上的点,存在m个区间,点可以安排在这些区间内,坐标为i,j的两个点的距离为|i−j|。 求这些点最小距离的最大值?
比如有三个点,区间为[1,2],[3,4],[5,7], 我们如果这三个点分别安排在1,3,7,这样最小距离为2;如果安排在1,4,7,这样最小距离为3。 这个例子中最小距离的最大值为3。
输入格式#
第一行是一个整数T(1≤T≤50),表示样例的个数。
每个样例的第一行是两个整数n (2≤n≤10000),m (1≤m≤10000)。
以后的m行,每行两个整数a,b, (1≤a<b≤109),表示整数点可以安排的区间。
输出格式#
每行输出一个样例的结果,如果为一个整数,那么输出整数;否则,输出一个分数,并保证分子与分母互质。
样例输入#
2 3 3 1 2 3 4 5 7 3 1 1 2样例输出#
3 1/2提示#
区间可能存在相交或者包含。
解题思路:注意本题答案可能是分数,但是分数计算好像不太方便,所以我们用 浮点数来代替计算。 具体步骤: 对区间排序、化简区间、 二分距离(浮点数)、把浮点数化成分数形式。如果分子/分母 的值 最接近 二分找到的那个浮点数,则把该分数定为目标答案。
分母大小其实是有范围的,最大的也就是 n-1。得出这个结论,是因为区间端点输入的是整数。所以在普通情况下,很多时候 当某个分数条件成立时,必有一个大于它的整数也成立。
比如 题目中 [1,2],[3,4],[5,7] , 距离:2.9 是成立的,则必然 3 也是成立的, 因为区间端点都是整数, 你若有一段距离选择 2.9,那么其他距离段中必然有多出来 0.1 可以被分回来给 2.9,即:把 0.1 补进 2.9 中也是能成立的。 但是如果某个区间 被 p 个点 整分,则答案可以为分数。 具体情况就沿这个思路往下考虑。
AC代码:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int T,n,m,cnt;
struct QuJian {
double a = 0, b = 0;
}abQJ[10010];
int cmp(const void *p1,const void *p2){
if ( ((QuJian *)p1)->a != ((QuJian *)p2)->a)
return ((QuJian *)p1)->a - ((QuJian *)p2)->a;
return ((QuJian *)p2)->b - ((QuJian *)p1)->b;
}
int gcd(int x,int y){
return y>0 ? gcd(y,x%y) : x;
}
void hebingQJ()
{
cnt = 0;
for (int i = 1; i < m; i ++)
{
if (abQJ[i].b < abQJ[cnt].b) continue;
if (abQJ[i].a < abQJ[cnt].b) abQJ[cnt].b = abQJ[i].b;
else
{
cnt ++;
abQJ[cnt].a = abQJ[i].a;
abQJ[cnt].b = abQJ[i].b;
}
}
}
bool check(double min_len)
{
int now = 0, num = 1;
double point = abQJ[0].a;
while (num < n && now <= cnt)
{ //如果距离相差 大于 min_len; 这里是验证 abQJ[now].b-point == min_len,如两浮点数差值 小于1e-6,我们看作两数相等
if (abQJ[now].b-point > min_len || fabs(abQJ[now].b-point-min_len) < 1e-6)
{
if (abQJ[now].a - point >= min_len)
point = abQJ[now].a;
else
point += min_len;
num ++;
}
else now ++;
}
if (num < n) return false;
return true;
}
int main()
{
scanf("%d",&T);
while (T --)
{
int fz, fm, gccd;
double left, right, mid, best;
scanf("%d %d",&n,&m);
for (int i = 0; i < m; i ++) // 输入区间
scanf("%lf %lf",&abQJ[i].a,&abQJ[i].b);
qsort(abQJ,m,sizeof(QuJian),cmp); // 给区间按左右端点排序
hebingQJ(); // 化简区间(合并 内含、相交的区间)
left = 0, right = abQJ[cnt].b-abQJ[0].a; // 浮点数二分查找
while (right-left > 1e-8) // 左右相差小于 1e-8, 则把其看成同一个数(精度)
{
mid = (left+right) / 2;
if (check(mid)) left = mid;
else right = mid;
}
best = 1e9; // 将浮点数化成 分数形式
for (int i = 1; i < n; i ++) // 分母取值范围 1 ~ n-1
{
int fz_ = round(left*i); // 分子
double t = fabs((double)fz_/i - left); // 分子/分母 - 浮点数。 t代表误差值
if (t < best) // 如果误差值更小, 更新更优的 分子分母组合。
{
best = t;
fz = fz_;
fm = i;
}
}
gccd = gcd(fz,fm);
fz /= gccd, fm /= gccd;
if (fm == 1) printf("%d\n",fz);
else printf("%d/%d\n",fz,fm);
}
return 0;
}