https://www.acmicpc.net/problem/7869
1. 아이디어
두 원이 교차하는 영역의 넓이는 두 원의 위치 관계에 따라 다르게 풀이한다.
두 원의 중심 사이의 거리가 두 원의 반지름의 길이의 합 보다 클 경우 두 원이 교차하는 영역이 없다.(두 원이 바깥에 서로 떨어진 경우)
두 원의 중심 사이의 거리가 두 원의 반지름의 차보다 작을 경우 두 원이 교차하는 영역은 작은 원의 넓이와 같다.(한 원이 다른 원을 포함하는 경우)
두 원이 두 개의 교점을 가지는 경우에는 두 원이 교차하는 영역의 넓이가 두 원이 만드는 현의 넓이의 합과 같음을 이용한다.
2. 문제풀이
두 현을 통해 넓이를 구하는 경우가 아닌 케이스를 먼저 조건으로 처리해줬다.
두 현의 넓이를 통해 교차하는 영역의 넓이를 구하는 케이스에서 현의 넓이는 부채꼴의 넓이 - 삼각형의 넓이라는 점을 활용했다.
제2코사인법칙으로 두 원의 교점과 원의 중심 사이의 각도를 구할 수 있고, 이 각도로 부채꼴의 넓이와 삼각형의 넓이를 구할 수 있다.
이때 각도가 180도를 넘어가는 경우 오히려 부채꼴 넓이에서 삼각형의 넓이를 더해야 현의 넓이가 되는데 삼각형의 넓이가 음수로 계산이 돼서 같은 로직으로 쭉 작성할 수 있는 점을 활용했다.
3. 코드
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
double x1 = Double.parseDouble(st.nextToken());
double y1 = Double.parseDouble(st.nextToken());
double r1 = Double.parseDouble(st.nextToken());
double x2 = Double.parseDouble(st.nextToken());
double y2 = Double.parseDouble(st.nextToken());
double r2 = Double.parseDouble(st.nextToken());
// 두 원의 중심 사이 거리
double d = distance(x1, y1, x2, y2);
// 두 원의 반지름의 합보다 중심 사이 거리가 멀면 교차하는 영역이 없음
if (d >= r1 + r2) {
System.out.println("0.000"); // String으로 출력안하면 0.0으로 출력됨
return;
// 한 원이 다른 원 내부에 있는 경우
} else if (d <= r1 - r2) {
System.out.printf("%.3f", areaOfCircle(r2));
return;
} else if (d <= r2 - r1) {
System.out.printf("%.3f", areaOfCircle(r1));
return;
}
double sector1 = areaOfSector(r1, 2 * angle(r1, d, r2));
double triangle1 = areaOfTriangle(r1, r1, 2 * angle(r1, d, r2));
double sector2 = areaOfSector(r2, 2 * angle(r2, d, r1));
double triangle2 = areaOfTriangle(r2, r2, 2 * angle(r2, d, r1));
// 부채꼴 넓이에서 삼각형 넓이를 뺀 현의 넓이로 교차하는 영역의 넓이를 구함
System.out.printf("%.3f", sector1 - triangle1 + sector2 - triangle2);
}
private static double distance(double x1, double y1, double x2, double y2) {
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
}
// 제2코사인법칙 응용
private static double angle(double a, double b, double c) {
return Math.acos((a * a + b * b - c * c) / (2 * a * b));
}
// 원의 넓이를 구하는 메서드
private static double areaOfCircle(double radius) {
return Math.PI * radius * radius;
}
// 부채꼴의 넓이를 구하는 메서드
private static double areaOfSector(double radius, double angle) {
return Math.PI * radius * radius * (angle / (2 * Math.PI));
}
// 삼각형의 넓이를 구하는 메서드
private static double areaOfTriangle(double a, double b, double angle) {
return 0.5 * a * b * Math.sin(angle);
}
}
4. 후기
'코딩테스트 준비 > 백준' 카테고리의 다른 글
[백준] 10808번 - 알파벳 개수 [Java] (0) | 2024.12.10 |
---|---|
[백준] 23756번 - 노브 돌리기 [Java] (0) | 2024.12.10 |
[백준] 10926번 - ??! [Java] (1) | 2024.12.09 |
[백준] 2857번 - FBI [Java] (0) | 2024.12.09 |
[백준] 12781번 - PIZZA ALVOLOC [Java] (0) | 2024.12.08 |