BOJ C++ 알고리즘 공부

[기하학] 두 원(7869) (C++)

kk_eezz 2022. 2. 11. 19:19

 

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

 

7869번: 두 원

첫째 줄에 두 원의 중심과 반지름 x1, y1, r1, x2, y2, r2가 주어진다. 실수는 최대 소수점 둘째자리까지 주어진다.

www.acmicpc.net

 

 

1. 문제 개요

 

2차원 평면상에 두 원이 주어질 때, 교차하는 영역의 넓이를 소수점 셋째자리 구하는 문제.

 

 

2. 입출력

 

 

3. 문제 풀이

 

두 원이 만나는 경우는 네가지로 나눌 수 있다.

 

 

첫번째는 두 원이 만나지 않는 경우이다.

이 경우에는 두 원의 중심의 거리가 두 원의 반지름을 합한 값보다 크다. 두 원이 교차하는 영역이 존재하지 않게 된다.

 

두번째는 한 원이 다른 원에 포함되지 않으면서 한 점에서 만나는 경우이다.

이 경우에는 두 원의 중심의 거리가 두 원의 반지름을 합한 값과 같다. 두 원이 교차하는 영역이 존재하지 않게 된다.

 

세번째로는 한 원이 다른 원에 포함되는 경우이다.

이 경우에는 두 원의 중심의 거리가 두 원의 반지름을 뺀값의 절댓값보다 작다. 다른 원에 포함된 원의 넓이가 두 원이 교차하는 영역의 넓이가 된다.

 

마지막으로는 두 원이 두 점에서 만나는 경우이다.

이 경우에는 아래와 같이 넓이를 구할 수 있다.

 

 


 

1. 두 원이 만나는 부분의 넓이는 두 원의 활꼴을 더해주면 구할 수 있다.

 

2. 활꼴의 넓이는 부채꼴에서 해당 각도의 삼각형을 빼주면 구할 수 있다.

여기서 중요한 것은 각 원의 부채꼴의 각도를 어떻게 구할 것인가이다.

 

 

3. 부채꼴의 각도는 코사인법칙을 통해 구할 수 있다.

 

 

코사인법칙의 정의: 

 

반지름이 r1인 원의 부채꼴의 각도를 포함한 코사인법칙은 다음과 같고, 아코사인함수에 코사인 값을 구하면 세타값을 구할 수 있다.

마지막으로 세타에 2를 곱해주기만 하면된다.

반지름이 r2인 원의 부채꼴의 각도 또한 r1과 r2 위치를 바꾸어주기만 하면 똑같이 구할 수 있다.

 

 

4. 전체 코드

#include <algorithm>
#include <stdio.h>
#include <vector>
#include <cmath>

using namespace std;
//두 원

int main()
{
    double x1, y1, r1, x2, y2, r2;
    scanf("%lf%lf%lf%lf%lf%lf",&x1,&y1,&r1,&x2,&y2,&r2);
    
    double d = sqrt(pow(x1-x2, 2) + pow(y1-y2, 2));
    
    if(d>=r1+r2) 
    {
        printf("0.000");
        
    } else if (d <= abs(r1-r2)) { //한 원이 다른 원을 포함하는 경우
        
        double radius = min(r1,r2);
        printf("%.3lf",round((radius*radius*M_PI)*1000)/1000);
        
    } else {
        
        double theta1 = acos((r1*r1 + d * d - r2 * r2)/(2*r1*d));
        double theta2 = acos((r2*r2 + d*d - r1*r1)/(2*r2*d));
        
        double triangular1 = r1 * r1 * sin(2*theta1)/2;
        double triangular2 = r2 * r2 * sin(2*theta2)/2;
       
        double s1 = (r1 * r1 * theta1) - triangular1;
        double s2 = (r2 * r2 * theta2) - triangular2;
      
        printf("%.3lf",round((s1+s2)*1000)/1000);
    }
    
    return 0;
}