7869번 : 두 원
두 원이 주어졌을 때, 교차하는 영역의 넓이를 소수점 셋째자리까지 구하는 프로그램을 작성하시오.
입력
첫째 줄에 두 원의 중심과 반지름 x1, y1, r1, x2, y2, r2가 주어진다. 실수는 최대 소수점 둘째자리까지 주어진다.
출력
첫째 줄에 교차하는 영역의 넓이를 반올림해 소수점 셋째자리까지 출력한다.
생각해 볼 점
제 2 코사인 법칙을 기억하고 있다면 상당히 쉽게 풀 수 있습니다.
코사인법칙, 제2 코사인법칙 증명 – 수학방 (mathbang.net)
겹치는 부분 = 부채꼴 너비의 합 - 마름모의 합
cos(theta / 2)로 정리하면,
arccos을 통해 theta / 2의 값을 구할 수 있으며,
r ^ 2 * sin(theta) / 2를 통해 각 삼각형의 너비를 구할 수 있습니다.
코드
#include <iostream>
#include <cmath>
using namespace std;
//원 구조체
struct circle
{
double x, y, r, half_theta;
circle(double const x, double const y, double const r)
{
this->x = x;
this->y = y;
this->r = r;
}
//B 원과의 거리
double get_distance(circle B) { return sqrt(pow((this->x - B.x), 2) + pow((this->y - B.y), 2)); }
//원의 중심의 두 원의 교점에 대한 각도의 절반을 구하는 함수
void set_half_theta(double const r2, double const d)
{
double const r1 = this->r;
//코사인 공식을 통해 유도됨
//r2 ^ 2 = r1 ^ 2 + d ^ 2 - r1 * d * cos(theta / 2)
half_theta = acos((d * d + r1 * r1 - r2 * r2) / (2 * d * r1));
}
static void solution(circle A, circle B, double const d)
{
//부채꼴 합 - 삼각형 합
double ans = ((2 * A.half_theta * A.r * A.r + 2 * B.half_theta * B.r * B.r) -
(A.r * A.r * sin(A.half_theta * 2) + B.r * B.r * sin(B.half_theta * 2))) / 2;
//네번째 자리에서 반올림
ans = round(ans * 1000) / 1000;
printf("%.3lf", ans);
}
};
int main()
{
double x, y, r;
scanf("%lf %lf %lf", &x, &y, &r);
circle A(x, y, r);
scanf("%lf %lf %lf", &x, &y, &r);
circle B(x, y, r);
double distance = A.get_distance(B);
//원이 겹치지 않음
if (A.r + B.r <= distance)
{
printf("0.000");
return 0;
}
//한쪽 원이 다른쪽 원에 포함됨
else if (distance <= abs(B.r - A.r))
{
double ans = pow(min(A.r, B.r), 2) * 3.14159265358979;
ans = round(ans * 1000) / 1000;
printf("%.3lf", ans);
return 0;
}
A.set_half_theta(B.r, distance);
B.set_half_theta(A.r, distance);
circle::solution(A, B, distance);
return 0;
}
그 외
'공부 및 정리 > 백준 코드' 카테고리의 다른 글
[C++]백준 - 1105번 문제 (0) | 2021.12.10 |
---|---|
[C++]백준 - 1069번 문제 (0) | 2021.12.10 |
[C++]백준 - 23082번 문제 (0) | 2021.12.06 |
[C++]백준 - 4600번 문제 (0) | 2021.12.06 |
[C++]백준 - 2467번 문제 (0) | 2021.12.04 |