본문 바로가기
코딩테스트 준비/백준

[백준] 7869번 - 두 원 [Java]

by mwzz6 2024. 12. 9.

https://www.acmicpc.net/problem/7869

 

[백준] 7869번 - 두 원 [Java]
[백준] 7869번 - 두 원 [Java]


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. 후기