luogu题解 UVA1615 【Highway】

  • 题目链接:

    https://www.luogu.org/problemnew/show/UVA1615

  • 分析:

    首先这里的距离是欧几里得距离而不是曼哈顿距离。

    然后我们对于每个点,求出在公路上保持D范围内最远的两个端点,这两个端点构成一个区间,我们要做的就是选出尽量少的点使所有区间至少有一个点,就是典型的区间选点问题。

    怎么做呢?把所有区间右端点从小到大排序,如果右端点相同左端点小的在前面。

    达到贪心的目的,我们设一个pos=-inf,然后遍历所有区间,如果pos>该区间左端点,cnt+1,pos=区间右端点,然后结合之前的排序方式就不难理解。

  • 注意:

    • 可能有些人不知道怎么求左右端点,这要用到一点解析几何知识,每个点((a,b))构成一个圆的方程((x-a)^2+(y-a)^2=d^2),然后将(y=0)带入就求出两个横坐标

    • 有多组数据

  • 代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <cmath>
using namespace std;
const int maxn=1000005;
struct Seg{
	double l,r;
	bool operator <(const Seg &b)const{
		if(r==b.r)return l>b.l;
		return r<b.r;
	}
}seg[maxn];
double l,d;
int n;
int main(){
	
	while(scanf("%lf %lf %d",&l,&d,&n)!=EOF){
	int cnt=0;
	for(register int i=1;i<=n;i++){
		double x,y;
		scanf("%lf %lf",&x,&y);
		double sqr=sqrt(d*d-y*y);
		seg[i].l=max(0.0,-sqr+x);
		seg[i].r=min(l,sqr+x);
	}
	sort(seg+1,seg+1+n);
	double pos=-19260817.0;
	for(register int i=1;i<=n;i++){
		if(seg[i].l>pos){
			pos=seg[i].r;
			cnt++;
		}
	}
	printf("%d
",cnt);
	memset(seg,0,sizeof(seg));
    }
		return 0;
}
原文地址:https://www.cnblogs.com/Rye-Catcher/p/9089877.html