#计算几何#POJ1375 UVA313 Intervals

题目传送门


分析

实际上就是 \((bx,by)\) 向圆作切线与 \(x\) 轴的交点形成一段区间,相当于变成了输出区间的并。

那么怎么把交点求出来呢,其实可以用解析几何来做,设切线方程为 \(x=m(y-by)+bx\),那么 \((cx,cy)\) 到该直线的距离为 \(r\)

也就是 \(\frac{|(cx-bx)-m(cy-by)|}{\sqrt{1+m^2}}=r\),转化为一元二次方程后直接套求根公式把两个根 \(m_1,m_2\) 求出来,那么交点横坐标就是 \(bx-m\cdot by\)


代码

#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long double ld;
int n; pair<ld,ld>a[511];
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
bool cmp(pair<ld,ld> x,pair<ld,ld> y){
	if (x.first!=y.first) return x.first<y.first;
	    else return x.second>y.second; 
}
int main(){
	while (n=iut()){
		ld X=iut(),Y=iut();
		for (int i=1;i<=n;++i){
			ld x=iut(),y=iut(),r=iut();
			ld A=(y-Y)*(y-Y)-r*r;
			ld B=-2*(x-X)*(y-Y);
			ld C=(x-X)*(x-X)-r*r;
			ld sqrtdelta=sqrt(B*B-4*A*C);
			ld L=(-B+sqrtdelta)/(2*A),R=(-B-sqrtdelta)/(2*A);
			L=X-L*Y,R=X-R*Y;
			if (L>R) swap(L,R);
			a[i]=make_pair(L,R);
		}
		sort(a+1,a+1+n,cmp);
		ld lst=a[1].first,Lst=lst;
		for (int i=1;i<=n;++i){
			if (a[i].second<=lst) continue;
			if (lst<a[i].first){
				printf("%.2Lf %.2Lf\n",Lst,lst);
				Lst=a[i].first;
			}
			lst=a[i].second;
		}
		if (Lst<lst) printf("%.2Lf %.2Lf\n",Lst,lst);
		putchar(10);
	}
	return 0;
}
posted @ 2025-07-17 07:16  lemondinosaur  阅读(7)  评论(0)    收藏  举报