文章目录
HDU-6097 Mindis【圆内两点经过圆上某点的最短距离】
有一个结论是:两个以一对互反演点为其中一个端点,以反演中心和反演圆上某个点为另两个点为端点的三角形,相似,且相似比与反演点与反演半径的比例有关。
AC核心代码:
int main()
{
int t; scanf("%d", &t);
while(t--)
{
point a, b;
double r, ans, len;
scanf("%lf %lf %lf %lf %lf",&r, &a.x, &a.y, &b.x, &b.y);
if(length(a) < eps) ans = 2 * r; //函数ptp(point a, point p, double r)输入要保证a和p不重合
else
{
len = length(a);
a = ptp(a, {0,0}, r);
b = ptp(b, {0,0}, r);
double dis = dis_to_line({0, 0}, a, b);
if(dcmp(dis, r) <= 0) ans = get_dis(a, b);
else
{
point e = (a + b) / 2;
e = norm(e) * r;
ans = get_dis(e, a) + get_dis(e, b);
}
ans = len * ans / r;
}
printf("%.8f\n",ans);
}
// system("pause");
return 0;
}
「ICPC 2013 杭州赛区」Problem of Apollonius
题意:求过两圆外一点,且与两圆外切的所有的圆。
题解:- 反演变换 - OI Wiki
有几个坑要注意:
- 公切线有可能过反演中心,此时要舍去。
- 直线反演后内外侧会反转。
内公切线反演后,与两圆一个内切一个外切,要舍去。
对于外公切线,当反演点与两圆中心在同侧时,反演后新圆与两圆外切,保留。
当反演点与两圆中心在异侧时,反演后新圆与两圆内切,舍去。
AC代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1e5+10;
typedef long long LL;
const double eps = 1e-7;
const double pi = acos(-1);
int dcmp(double x, double y){
if(fabs(x-y) < eps) return 0;
if(x < y) return -1;
return 1;
}
int sign(double x){
if(fabs(x) < eps) return 0;
if(x < 0) return -1;
return 1;
}
struct point{
double x,y;
point (double x=0, double y=0):x(x),y(y){}
bool operator < (point a){
if(dcmp(x, a.x)) return dcmp(x, a.x) < 0;
return dcmp(y, a.y) < 0;
}
bool operator == (point a) { return !dcmp(x, a.x) && !dcmp(y, a.y); }
};
point operator + (point a, point b) { return {a.x + b.x, a.y + b.y}; }
point operator - (point a, point b) { return {a.x - b.x, a.y - b.y}; }
point operator * (point a, double b) { return {a.x * b, a.y * b}; }
point operator / (point a, double b) { return {a.x / b, a.y / b}; }
double dot(point a, point b) { return a.x * b.x + a.y * b.y; }
double cross(point a, point b) { return a.x * b.y - a.y * b.x; }
double area(point a, point b, point c) { return cross(b - a, c - a) / 2; }
double length(point a) { return sqrt(a.x * a.x + a.y * a.y); }
double project(point a, point b, point c) { return dot(c - a, b - a) / length(b - a); }
point rotate(point a, double rad) { return {a.x * cos(rad) - a.y * sin(rad), a.x * sin(rad) + a.y * cos(rad)}; }
point norm(point a) { return a / length(a); }
double get_dis(point a, point b) { return length(a - b); }
double dis_to_line(point p, point a,point b)
{
if(a == b) return get_dis(p, a);
point v1 = b - a, v2 = p - a;
return fabs(cross(v1, v2) / length(v1));
}
//圆
struct circle{
point o;
double r;
point norm(double rad) { return {o.x + r * cos(rad),o.y + r * sin(rad)}; } // 返回圆上圆心角为rad的点
};
circle ctc(circle c, point p, double r)
{
circle res;
double t = get_dis(p, c.o);
double x = r * r / (t - c.r), y = r * r / (t + c.r);
res.r = (x - y) / 2;
double s = (x + y) / 2;
res.o = p + norm(c.o - p) * s;
return res;
}
circle ltc(point a, point b, point p, double r)
{
double d = dis_to_line(p, a, b);
d = r * r / d;
circle res;
res.r = d / 2;
point v;
if(area(a, b, p) > 0) v = rotate(b - a, -pi/2);
else v = rotate(a - b, -pi/2);
res.o = p + norm(v) * res.r;
return res;
}
int get_tangents(circle A, circle B, point* a, point* b)
{
int cnt = 0;
if(dcmp(A.r, B.r) < 0) {swap(A, B);swap(a, b);}
double d2 = (A.o.x - B.o.x)*(A.o.x - B.o.x) + (A.o.y - B.o.y)*(A.o.y - B.o.y); //圆心距离
double base = atan2(B.o.y - A.o.y, B.o.x - A.o.x); // AB向量的极角,A位大圆
double ang = acos((A.r - B.r) / sqrt(d2));//外公切线的图
// cout<<"### "<<d2<<" "<<base<<" "<<ang<<endl;
a[cnt] = A.norm(base + ang); b[cnt] = B.norm(base + ang); cnt++;
a[cnt] = A.norm(base - ang); b[cnt] = B.norm(base - ang); cnt++;
return cnt;
}
circle A, B;
point C;
point ta[10], tb[10];
point ansa[10], ansb[10];
int pos;
int main()
{
int t; scanf("%d", &t);
while(t--)
{
pos = 0;
scanf("%lf %lf %lf %lf %lf %lf %lf %lf", &A.o.x, &A.o.y, &A.r, &B.o.x, &B.o.y, &B.r, &C.x, &C.y);
A = ctc(A, C, 10); B = ctc(B, C, 10);
// cout<<"## "<<A.o.x<<" "<<A.o.y<<" "<<A.r<<endl<<B.o.x<<" "<<B.o.y<<" "<<B.r<<endl;
int cnt = get_tangents(A, B, ta, tb);
for(int i=0; i<cnt; i++)
if(sign(area(ta[i], tb[i], C)) && sign(area(ta[i], tb[i], C)) * sign(area(ta[i], tb[i], A.o)) >= 0) ansa[pos] = ta[i], ansb[pos++] = tb[i];
// for(int i=0; i<cnt; i++) cout<<"# "<<ta[i].x<<" "<<ta[i].y<<endl<<tb[i].x<<" "<<tb[i].y<<endl;
printf("%d\n", pos);
for(int i=0; i<pos; i++)
{
circle ans = ltc(ansa[i], ansb[i], C, 10);
// cout<<"# "<<ansa[i].x <<" "<<ansa[i].y<<" "<<ansb[i].x<<" "<<ansb[i].y<<endl;
if(fabs(ans.o.x) < eps) ans.o.x = 0;
if(fabs(ans.o.y) < eps) ans.o.y = 0;
printf("%.6f %.6f %.6f\n", ans.o.x, ans.o.y, ans.r);
}
}
return 0;
}