본문 바로가기

PROGRAMMING/Algorithm

[기하학] BOJ 7869 - 두 원 (두 원이 교차하는 영역의 넓이)

문제
두 원이 주어졌을 때, 교차하는 영역의 넓이를 소수점 셋째자리까지 구하는 프로그램을 작성하시오.
입력
첫째 줄에 두 원의 중심과 반지름 x1, y1, r1, x2, y2, r2가 주어진다. 실수는 최대 소수점 둘째자리까지 주어진다.
출력
첫째 줄에 교차하는 영역의 넓이를 반올림해 소수점 셋째자리까지 출력한다.

 

수능 수학영역에서 나올 법한 기하 문제이다. 풀이에 피타고라스의 정리와 삼각함수(코사인 법칙)를 사용하였다.

먼저, 주어진 문제에서 추가적인 조건 없이 두 원의 중심 좌표(x, y)와 반지름의 길이(r)가 주어졌다. 나올 수 있는 넓이를 구하는 데 사용되는 방식을 두 원의 중심 사이의 거리와 각각의 반지름의 관계에 따라 나누어야 한다.

따라서 아래와 같이 세 가지 경우로 표현하고 연산 방식을 분기할 수 있다.


두 원이 만나지 않는 경우

두 원의 중심의 사이의 거리가 r1 + r2 보다 큰 경우이다.

이 경우 두 원의 어떤 부분도 교차하지 않으므로 넓이 S = 0 이다.


하나의 원이 다른 원 안에 완전히 포함되는 경우

두 원의 중심의 사이의 거리가 |r1 - r2| 보다 작거나 같을 경우이다.

이 경우 두 원이 교차하는 영역의 넓이는 두 원 중의 작은 원의 넓이이다. 따라서 넓이 S = PI * pow(min(r1, r2), 2) 이다.


두 원의 일부가 서로 만나는 경우

위 두의 경우를 제외한 모든 경우이다. 이 문제의 핵심인 경우라고 볼 수 있으며 세 개의 경우 중 가장 복잡한 풀이 방식을 사용한다.


먼저, 두 원의 중심을 각각 O₁, O₂ 라 하고, 두 원의 테두리가 만나는 두 점을 각각 P, P' 라고 하면 다음과 같이 선분 O₁P, O₁P', O₂P, O₂P', PP' 를 만들 수 있다.

이 때, 두 원은 호 PP'를 가지는 부채꼴과 원의 중심과 점 P, P'을 꼭짓점으로 가지는 삼각형을 만들 수 있다. 여기서 두 원이 교차하는 영역의 넓이를 부분을 구하려면 각 원에서 만들어진 부채꼴의 넓이에 삼각형의 넓이를 뺀 넓이를 서로 더하면 된다.

각 원에 대한 부채꼴의 넓이를 구하려면 먼저 그 부채꼴에 대한 중심각의 크기 θ를 구해야한다. 또한 삼각형의 넓이는 반지름인 두 변의 길이와 사잇각의 크기 θ로 구할 수 있으므로 두 부채꼴의 중심각 θ₁, θ₂ 을 먼저 구해보자.


먼저, 위와 같이 삼각형 O₁O₂P와 삼각형 O₁O₂P'을 만들 수 있다. 이때, 선분 O₁O₂의 길이는 두 원의 중심의 거리 d이고, 삼각형 O₁O₂P와 삼각형 O₁O₂P'는 세 변의 길이가 모두 같은 SSS 합동이므로 각 PO₁O₂의 크기는 θ₁ / 2 이다.

여기서 삼각형 O₁O₂P의 길이를 모두 알고 있으므로 코사인 제 2법칙을 이용하여 다음과 같은 식을 만들 수 있다.

이 식을 θ₁에 대해서 전개하면, 코사인의 역함수를 이용하여 θ₁을 구할 수 있게 된다.

θ₂ 에 대해서도 다음과 같이 식을 정리할 수 있다.


두 부채꼴의 중심각 θ₁, θ₂를 모두 구했으니, 반지름과 중심각을 이용하여 부채꼴과 삼각형의 넓이를 구할 수 있게 되었다. S₁가 두 원에서 만들어진 부채꼴의 넓이의 합이고, S₂가 두 원에서 만들어진 삼각형의 넓이의 합이면 다음과 같이 식을 쓸 수 있다.

최종적으로 구하고자 하는 넓이 S(두 원의 교차하는 영역의 넓이)는 S₁에 S₂를 빼면 되므로 이렇게 식을 정리할 수 있다.

컴퓨터 알고리즘으로 구현할 경우 θ₁, θ₂ 을 먼저 실수형 변수로 저장하고 이 두 변수를 이용하여 넓이 S를 구하도록 하면 된다. S를 출력하는데 있어 소수점 셋째자리까지 반올림하는것에 주의가 필요하다.


소스 코드
#include <stdio.h>
#include <math.h>

int main()
{
	double x1, y1, r1, t1, x2, y2, r2, t2, d, result;
	scanf("%lf %lf %lf %lf %lf %lf", &x1, &y1, &r1, &x2, &y2, &r2);

	d = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
	if (r1 + r2 <= d)
		result = 0.0;
	else if (fabs(r1 - r2) >= d)
		result = 3.14159265359 * fmin(r1 * r1, r2 * r2);
	else
	{
		t1 = acos((d * d + r1 * r1 - r2 * r2) / (d * r1 * 2.0)) * 2.0;
		t2 = acos((d * d + r2 * r2 - r1 * r1) / (d * r2 * 2.0)) * 2.0;

		result = (t1 * r1 * r1 + t2 * r2 * r2 - r1 * r1 * sin(t1) - r2 * r2 * sin(t2)) * 0.5;
	}

	printf("%.3lf\n", result);
	return 0;
}