double distance_sqr(struct point_t const* a, struct point_t const* b)
return (a->x - b->x) * (a->x - b->x) + (a->y - b->y) * (a->y - b->y);
* circles[0] 和 circles[1] 分别是两个圆.
* 如果用到了两个交点, 那么返回后, 横坐标大的在前, 如果横坐标一样, 则纵坐标大的在前.
* 其它整数值: 交点个数.
int insect(struct circle_t circles[], struct point_t points[])
{
double d, a, b, c, p, q, r; // a, b, c, p, q, r 与上面分析中的量一致
double cos_value[2], sin_value[2]; // 交点的在 circles[0] 上对应的正余弦取值
// 余弦值 cos_value 就是分析中的 cosθ
if (double_equals(circles[0].center.x, circles[1].center.x)
&& double_equals(circles[0].center.y, circles[1].center.y)
&& double_equals(circles[0].r, circles[1].r)) {
return -1;
}
d = distance(&circles[0].center, &circles[1].center); // 圆心距离
if (d > circles[0].r + circles[1].r
|| d < fabs(circles[0].r - circles[1].r)) {
return 0;
}
a = 2.0 * circles[0].r * (circles[0].center.x - circles[1].center.x);
b = 2.0 * circles[0].r * (circles[0].center.y - circles[1].center.y);
c = circles[1].r * circles[1].r - circles[0].r * circles[0].r
- distance_sqr(&circles[0].center, &circles[1].center);
p = a * a + b * b;
q = -2.0 * a * c;
// 如果交点仅一个
if (double_equals(d, circles[0].r + circles[1].r)
|| double_equals(d, fabs(circles[0].r - circles[1].r))) {
cos_value[0] = -q / p / 2.0;
sin_value[0] = sqrt(1 - cos_value[0] * cos_value[0]);
points[0].x = circles[0].r * cos_value[0] + circles[0].center.x;
points[0].y = circles[0].r * sin_value[0] + circles[0].center.y;
// 在这里验证解是否正确, 如果不正确, 则将纵坐标符号进行变换
if(!double_equals(distance_sqr(&points[0], &circles[1].center),
circles[1].r * circles[1].r)) {
points[0].y = circles[0].center.y - circles[0].r * sin_value[0];
}
return 1;
}
r = c * c - b * b;
cos_value[0] = (sqrt(q * q - 4.0 * p * r) - q) / p / 2.0;
cos_value[1] = (-sqrt(q * q - 4.0 * p * r) - q) / p / 2.0;
sin_value[0] = sqrt(1 - cos_value[0] * cos_value[0]);
sin_value[1] = sqrt(1 - cos_value[1] * cos_value[1]);
points[0].x = circles[0].r * cos_value[0] + circles[0].center.x;
points[1].x = circles[0].r * cos_value[1] + circles[0].center.x;
points[0].y = circles[0].r * sin_value[0] + circles[0].center.y;
points[1].y = circles[0].r * sin_value[1] + circles[0].center.y;
// 验证解是否正确, 两个解都需要验证.
if (!double_equals(distance_sqr(&points[0], &circles[1].center),
circles[1].r * circles[1].r)) {
points[0].y = circles[0].center.y - circles[0].r * sin_value[0];
}
if (!double_equals(distance_sqr(&points[1], &circles[1].center),
circles[1].r * circles[1].r)) {
points[1].y = circles[0].center.y - circles[0].r * sin_value[1];
}
// 如果求得的两个点坐标相同, 则必然其中一个点的纵坐标反号可以求得另一点坐标
if (double_equals(points[0].y, points[1].y)
&& double_equals(points[0].x, points[1].x)) {
if(points[0].y > 0) {
points[1].y = -points[1].y;
} else {
points[0].y = -points[0].y;
}
}
return 2;
}
NP 问题的启示
NP 问题教导我们, 验证比求解要简单! 虽然这一道题, 无论怎么看, 都是一个普通的 P 问题, 但是我们还是可以贯彻这一思想, 用最简易的手法获得答案.
一个完整的程序:
#include
#include
struct point_t {
double x, y;
};
struct circle_t {
struct point_t center;
double r;
};
int double_equals(double const a, double const b)
{
static const double ZERO = 1e-9;
return fabs(a - b) < ZERO;
}
double distance_sqr(struct point_t const* a, struct point_t const* b)
{
return (a->x - b->x) * (a->x - b->x) + (a->y - b->y) * (a->y - b->y);
}
double distance(struct point_t const* a, struct point_t const* b)
{
return sqrt(distance_sqr(a, b));
}
int insect(struct circle_t circles[], struct point_t points[])
{
double d, a, b, c, p, q, r;
double cos_value[2], sin_value[2];
if (double_equals(circles[0].center.x, circles[1].center.x)
&& double_equals(circles[0].center.y, circles[1].center.y)
&& double_equals(circles[0].r, circles[1].r)) {
return -1;
}
d = distance(&circles[0].center, &circles[1].center);
if (d > circles[0].r + circles[1].r
|| d < fabs(circles[0].r - circles[1].r)) {
return 0;
}
a = 2.0 * circles[0].r * (circles[0].center.x - circles[1].center.x);
b = 2.0 * circles[0].r * (circles[0].center.y - circles[1].center.y);
c = circles[1].r * circles[1].r - circles[0].r * circles[0].r
- distance_sqr(&circles[0].center, &circles[1].center);
p = a * a + b * b;
q = -2.0 * a * c;
if (double_equals(d, circles[0].r + circles[1].r)
|| double_equals(d, fabs(circles[0].r - circles[1].r))) {
cos_value[0] = -q / p / 2.0;
sin_value[0] = sqrt(1 - cos_value[0] * cos_value[0]);
points[0].x = circles[0].r * cos_value[0] + circles[0].center.x;
points[0].y = circles[0].r * sin_value[0] + circles[0].center.y;
if (!double_equals(distance_sqr(&points[0], &circles[1].center),
circles[1].r * circles[1].r)) {
points[0].y = circles[0].center.y - circles[0].r * sin_value[0];
}
return 1;
}
r = c * c - b * b;
cos_value[0] = (sqrt(q * q - 4.0 * p * r) - q) / p / 2.0;
cos_value[1] = (-sqrt(q * q - 4.0 * p * r) - q) / p / 2.0;
sin_value[0] = sqrt(1 - cos_value[0] * cos_value[0]);
sin_value[1] = sqrt(1 - cos_value[1] * cos_value[1]);
points[0].x = circles[0].r * cos_value[0] + circles[0].center.x;
points[1].x = circles[0].r * cos_value[1] + circles[0].center.x;
points[0].y = circles[0].r * sin_value[0] + circles[0].center.y;
points[1].y = circles[0].r * sin_value[1] + circles[0].center.y;
if (!double_equals(distance_sqr(&points[0], &circles[1].center),
circles[1].r * circles[1].r)) {
points[0].y = circles[0].center.y - circles[0].r * sin_value[0];
}
if (!double_equals(distance_sqr(&points[1], &circles[1].center),
circles[1].r * circles[1].r)) {
points[1].y = circles[0].center.y - circles[0].r * sin_value[1];
}
if (double_equals(points[0].y, points[1].y)
&& double_equals(points[0].x, points[1].x)) {
if (points[0].y > 0) {
points[1].y = -points[1].y;
} else {
points[0].y = -points[0].y;
}
}
return 2;
}
int main()
{
struct circle_t circles[2];
struct point_t points[2];
while (EOF != scanf("%lf%lf%lf%lf%lf%lf",
&circles[0].center.x, &circles[0].center.y, &circles[0].r,
&circles[1].center.x, &circles[1].center.y, &circles[1].r)) {
switch (insect(circles, points)) {
case -1:
printf("THE CIRCLES ARE THE SAME/n");
break;
case 0:
printf("NO INTERSECTION/n");
break;
case 1:
printf("(%.3lf %.3lf)/n", points[0].x, points[0].y);
break;
case 2:
printf("(%.3lf %.3lf) (%.3lf %.3lf)/n",
points[0].x, points[0].y,
points[1].x, points[1].y);
}
}
return 0;
}
转帖自:道庭的blog
http://sites.google.com/site/lene13/Home/pure-mass/0