[백준알고리즘] 3053번: 택시 기하학 -Python, C++
3053번: 택시 기하학
첫째 줄에는 유클리드 기하학에서 반지름이 R인 원의 넓이를, 둘째 줄에는 택시 기하학에서 반지름이 R인 원의 넓이를 출력한다. 정답과의 오차는 0.0001까지 허용한다.
www.acmicpc.net
유클리드 거리(Euclidean distance)와 택시 거리(맨하탄 거리, Manhattan distance)에 대한 내용을 다루고 있다.
유클리드 거리는 어릴 때 배우는 피타고라스 정리에 의한 거리 계산 방법이다.
두 점 \((x_1, x_2)\)와 \((y_1, y_2)\) 사이의 거리는 \(\sqrt{(x_1 - y_1)^2 + (x_2 - y_2)^2}\)이다.
반면 맨해튼 거리는 두 점 사이의 거리를 유클리드 거리 방식과 다르게 구한다.
두 점 \((x_1, x_2)\)와 \((y_1, y_2)\) 사이의 거리는 \(|x_1-y_1| + |x_2-y_2|\)이다.
아래는 유명한 그림으로 위키피디아에 있는 걸 가져왔다.
가장 왼쪽 아래에 있는 점에서 오른쪽 위의 점 사이의 거리를 구하려고 할 때 유클리드 거리는 가운데 녹색 선과 일치한다.
그리고 정의에 따른 맨해튼 거리는 빨간색 선과 일치할 것이다.
하지만 잘 살펴보면 빨간색, 파란색, 노란색 선은 모두 길이가 같다는 것을 알 수 있다. 이것이 맨하탄 거리의 특징이다.
아무튼 이 문제는 예전에 파이썬으로도 풀었는데 파이썬으로는 너무 쉽게 풀려서 그런가 포스팅을 안 했었다. 그래서 지금 쓰는 김에 써보려고 한다. 파이썬 코드는 C++ 코드 아래에 적어두었다.
C++로 푸는 데 있어서 PI 상수가 어디에 위치해있는지 찾아야 했다. 방법은 다양하게 있었다.
- #define _USE_MATH_DEFINES 선언 후 <math.h> 헤더의 M_PI 상수를 이용
- <cmath>의 acos를 사용해서 acos(-1)을 통해 PI 상수 생성
- <cmath>의 atan을 사용해서 atan(1) * 4로 PI 상수 생성
- boost::math::constants::pi를 사용
- <numbers>의 pi 상수 이용
위의 방법 중 4번을 제외하고 시도해보았다.
1번 방법인 <math.h>
헤더의 M_PI
를 시도해보았는데, 이상하게 <cmath>
로는 동작을 하지 않았다. 흠..
근데 C++을 하면서 굳이 C언어 형태의 <math.h>
헤더를 사용하고 싶지는 않아서 acos
를 사용해서 문제를 해결했다.
5번 방법의 경우에는 C++ 20에 새로 추가되었다고 한다. <numbers>
헤더를 포함시키고 std::numbers::pi
를 사용하면 된다.
출력 단위도 고려해줘야 한다. 입력되는 반지름이 10000 이하의 자연수이지만 1/1000의 정확도를 가지며 소수점 6번째 자리까지 출력을 하기 때문에 float
을 사용하면 틀렸다고 뜬다.
따라서 double
을 사용해주고 std::fixed
와 std::precision
을 사용했다.
fixed
의 경우에는 부동소수점 방식의 실수형을 고정소수점으로 만드는 것이다. 보통의 실수형은 더 큰 수를 표현할 수 있는 부동소수점 방식을 취하는데, 여기서 fixed
를 사용해주는 것은 precision
을 통해 소수점 아래 자릿수를 고정시키기 위함이다.
precision
같은 경우에는 원래 정수부와 소수부를 합친 모든 숫자의 최대 개수를 의미한다. 하지만 fixed
가 cout
에 설정되어 있다면 precision
은 소수점 아래의 정확도를 의미하게 된다. 따라서 소수점 정확도보다 낮은 값이 들어오면 반올림으로 소수점 아래 자리수를 맞춰주며 정확도보다 큰 값이 들어오면 \(0 padding\)을 해준다.
#include <iostream>
#include <cmath>
#define PI acos(-1) // atan(1) * 4
void solve(void);
int main(void)
{
solve();
}
void solve(void)
{
double r;
std::cin >> r;
std::cout << std::fixed;
std::cout.precision(6);
std::cout << r * r * PI << std::endl;
std::cout << r * r * 2 << std::endl;
}
아래는 파이썬 코드다.
from math import pi
r = int(input())
print("{:.6f}".format(pi * (r ** 2)))
print("{:.6f}".format(2 * (r ** 2)))
잘못된 점이나 부족한 점 지적해주시면 감사하겠습니다
'algorithm > 백준알고리즘' 카테고리의 다른 글
[백준알고리즘] 10872번: 팩토리얼 -Python, C++ (0) | 2021.01.19 |
---|---|
[백준알고리즘] 1002번: 터렛 -Python, C++ (0) | 2021.01.19 |
[백준알고리즘] 4153번: 직각삼각형 -C++ (0) | 2021.01.18 |
[백준알고리즘] 1085번: 직사각형에서 탈출 -C++ (0) | 2021.01.18 |
[백준알고리즘] 9020번: 골드바흐의 추측 -C++ (0) | 2021.01.18 |