Hit! Gym - 101522H (1)“二分”
题意:
分别给出两个圆的圆心坐标和半径长度,并保证两个圆有公共部分(相交/相切/内含),输出一个位于公共部分的点的坐标,答案不唯一。
注意一下距离的精度10^-5。
思路:
(1)暴力模拟。
这是我最初的想法,就是扫遍以两个圆心为对角顶点的矩形内的“每一个点”(误差允许范围内)。因为在大一的时候有学长讲过一个相关的题目。然而,-100 <= x, y <= 100,1 <= r <= 100, 距离的精度为10^-5,试过了会超时。然后,我尝试将精度减为10^-3,想试一下,果然WA,蠢。
(2)二分法。
连接两个圆心,在这条连接两个圆心的线段上,一定存在一点符合条件。在以两个圆心为端点的区间上,进行二分搜索,判断点是否同时在两个圆内。
(1)ac代码
#include <stdio.h>
#include <math.h>
double // 两点间的距离
F(double x, double y, double a, double b) {
double d;
d = sqrt((a - x) * (a - x) + (b - y) * (b - y));
return d;
}
int
main() {
double x1, y1, r1, x2, y2, r2, x, y, lx, ly, rx, ry, d1, d2;
scanf("%lf %lf %lf %lf %lf %lf", &x1, &y1, &r1, &x2, &y2, &r2);
// 不能直接用x1, x2, y1, y2二分,后面求距离时会用到,满屏WA的收获
lx = x1, ly = y1, rx = x2, ry = y2;
// while( 1 ), 而不是while( lx <= rx ) / while( ly <= ry ),
// 因为两个圆的圆心可能同时在x / y轴,或与x / y轴平行的直线上
while( 1 ) {
x = (lx + rx) / 2;
y = (ly + ry) / 2;
d1 = F(x1, y1, x, y);
d2 = F(x2, y2, x, y);
if( d1 <= r1 && d2 <= r2 ) {
printf("%f %f\n", x, y);
break;
}
else if( d1 <= r1 ) {
lx = x;
ly = y;
}
else if( d2 <= r2 ) {
rx = x;
ry = y;
}
}
return 0;
}
(2)why while( 1 )? not while( lx <= rx ) or while( ly <= ry )
(3)总结一下
function(1):
判断点(a, b)是否在以(x, y)为圆心,半径为r的圆内
function(2):
给出x,两点式求出对应的y坐标(斜率不存在,两点式求直线方程时分母为0)
function(3):
两点间的距离
方法1:function(1) + function(2) + 对x进行二分
方法2:function(1) + 对x, y同时进行二分
方法3:function(3) + 对x, y同时进行二分
(4)暴力模拟,WA
#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;
int // 判断点(a, b)是否在以(x, y)为圆心,半径为r的圆内
f(double x, double y, double r, double a, double b) {
double t;
t = sqrt((a - x) * (a - x) + (b - y) * (b - y));
if( t - r < 0.00001 ) {
return 1;
}
return 0;
}
int
main() {
double x1, y1, r1, x2, y2, r2, xl, xr, yd, yu, i, j;
int flag = 0;
scanf("%lf %lf %lf %lf %lf %lf", &x1, &y1, &r1, &x2, &y2, &r2);
xl = min(x1, x2);
xr = max(x1, x2);
yd = min(y1, y2);
yu = max(y1, y2);
//printf("%f %f %f %f\n", xl, xr, yd, yu);
for( i = xl; i < xr; i += 0.001 ) {
for( j = yd; j < yu; j += 0.001 ) {
// 点在两个圆的相交部分?
if( f(x1, y1, r1, i, j) == 1 && f(x2, y2, r2, i, j) == 1 ) {
printf("%f %f\n", i, j);
flag = 1;
break;
}
}
if( flag == 1 ) {
break;
}
}
return 0;
}