hdu 4773 圓的反演變換

Problem of Apollonius

                                                                          Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
                                                                           Total Submission(s): 744    Accepted Submission(s): 182
Special Judge


Problem Description
  Apollonius of Perga (ca. 262 BC - ca. 190 BC) was a Greek geometer and astronomer. In his noted work Epaphai, he posed and solved such a problem: constructing circles that are tangent to three given circles in a plane. Two tangent circles can be internally or externally tangent to each other, thus Apollonius's problem generically have eight solutions. 
  Now considering a simplified case of Apollonius's problem: constructing circles that are externally tangent to two given circles, and touches a given point(the given point must be on the circle which you find, can't be inside the circle). In addition, two given circles have no common points, and neither of them are contained by the other, and the given point is also located strictly outside the given circles. You should be thankful that modern mathematics provides you with plenty of useful tools other than euclidean geometry that help you a lot in this problem.
 

Input
  The first line of input contains an integer T (T ≤ 200), indicating the number of cases.
  Each ease has eight positive integers x1, y1, r1, x2, y2, r2, x3, y3 in a single line, stating two circles whose centres are (x1, y1), (x2, y2) and radius are r1 and r2 respectively, and a point located at (x3, y3). All integers are no larger than one hundred.
 

Output
  For each case, firstly output an integer S, indicating the number of solutions.
  Then output S lines, each line contains three float numbers x, y and r, meaning that a circle, whose center is (x, y) and radius is r, is a solution to this case. If there are multiple solutions (S > 1), outputing them in any order is OK. Your answer will be accepted if your absolute error for each number is no more than 10-4
 

Sample Input
1 12 10 1 8 10 1 10 10
 

Sample Output
2 10.00000000 8.50000000 1.50000000 10.00000000 11.50000000 1.50000000
Hint
This problem is special judged.
 

可以參考一下這篇博客:http://blog.csdn.net/acdreamers/article/details/16966369#comments

給定不相交的兩個圓以及圓外一點,找一個經過給定點的圓與其他兩個圓相切

首先來看反演變換,首先是給定一個圓圓心爲O,半徑爲R

1、圓外一點P與圓內一點P‘會一一對應的反演OP*OP'=R*R

2、經過O的圓,反演後成爲不經過O的一條直線

3、不經過O的圓,反演後成爲另一個圓,且圓心並不對應

4、不經過O的直線反演後成爲一個經過O的圓

5、過O的直線反演後不變

那麼這道題就把兩個圓反演之後求兩圓的公切線,然後反演回去,就會成爲一個過O的圓,且與另兩圓相切(由反演的過程可看出)

求反演後的圓的圓心,可以將過O的直線所在的那條直徑兩端點反演,然後再求圓心.

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
using namespace std;
double const eps = 1e-8;
struct Point
{
	double x, y;
	Point(double a = 1.0, double b = 1.0) :x(a), y(b) {}
	Point operator + (const Point &a)
	{
		return Point(x + a.x, y + a.y);
	}
	Point operator - (const Point &a)
	{
		return Point(x - a.x, y - a.y);
	}
	Point operator * (const double a)
	{
		return Point(a*x, a*y);
	}
	Point Trans()
	{
		return Point(-y, x);
	}
	void Input()
	{
		scanf("%lf%lf", &x, &y);
	}
};
struct Circle
{
	Point o;
	double r;
	Circle(Point a = Point(), double b = 1.0) :o(a), r(b) {}
	Point getPoint(double alpha)
	{
		return o + Point(r*cos(alpha), r*sin(alpha));
	}
	void Input()
	{
		o.Input();
		scanf("%lf", &r);
	}
	void Output()
	{
		printf("%.8lf %.8lf %.8lf\n", o.x, o.y, r);
	}
};
Point p;
Circle c[15];
double dist(Point A, Point B)
{
	return sqrt((A.x - B.x)*(A.x - B.x) + (A.y - B.y)*(A.y - B.y));
}
double cross(Point A, Point B, Point C)
{
	return (B.x - A.x)*(C.y - A.y) - (B.y - A.y)*(C.x - A.x);
}
int sign(double x)
{
	return (x > eps) - (x < -eps);
}
Circle Inverse(Circle C)
{
	Circle T;
	double t = dist(C.o, p);
	double x = 1.0 / (t - C.r);
	double y = 1.0 / (t + C.r);
	T.r = (x - y) / 2.0;
	double s = (x + y) / 2.0;
	T.o = p + (C.o - p) * (s / t);
	return T;
}
void add(Point a, Point b, int &k)
{
	double t = cross(a, p, b);
	if (t < 0) t = -t;
	double d = dist(a, b);
	t /= d;
	if (t > eps)
	{
		double w = 0.5 / t;
		Point dir = (b - a).Trans();
		Point a1 = p + dir * (w / d);
		Point b1 = p - dir * (w / d);
		if (fabs(cross(a, b, a1)) < fabs(cross(a, b, b1)))
			c[k++] = Circle(a1, w);
		else
			c[k++] = Circle(b1, w);
	}
}
int Work()
{
	c[0] = Inverse(c[0]);
	c[1] = Inverse(c[1]);
	if (c[1].r > c[0].r) swap(c[1], c[0]);
	Point v = c[1].o - c[0].o;
	double alpha = atan2(v.y, v.x);
	double d = dist(c[0].o, c[1].o);
	double beta = acos((c[0].r - c[1].r) / d);
	int k = 2;
	Point a = c[0].getPoint(alpha + beta);
	Point b = c[1].getPoint(alpha + beta);
	if (sign(cross(a, c[0].o, b)) == sign(cross(a, p, b)) &&	sign(cross(a, c[1].o, b)) == sign(cross(a, p, b)))
		add(a, b, k);
	a = c[0].getPoint(alpha - beta);
	b = c[1].getPoint(alpha - beta);
	if (sign(cross(a, c[0].o, b)) == sign(cross(a, p, b)) &&sign(cross(a, c[1].o, b)) == sign(cross(a, p, b)))
		add(a, b, k);
	return k - 2;
}
int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		c[0].Input();
		c[1].Input();
		p.Input();
		int num = Work();
		printf("%d\n", num);
		for (int i = 0;i<num;i++)
			c[i + 2].Output();
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章