$$\newcommand{\Z}{\mathbb{Z}} \newcommand{\R}{\mathbb{R}} \newcommand{\Q}{\mathbb{Q}} \newcommand{\N}{\mathbb{N}}\newcommand{\C}{\mathbb{C}} \newcommand{\oiv}[1]{\left] #1 \right[} \newcommand{\civ}[1]{\left[ #1 \right]} \newcommand{\ad}[1]{\text{ad}(#1)} \newcommand{\acc}[1]{\text{acc}(#1)} \newcommand{\Setcond}[2]{ \left\{\, #1 \mid #2 \, \right\}} \newcommand{\Set}[1]{ \left\{ #1 \right\}} \newcommand{\abs}[1]{ \left\lvert #1 \right\rvert}\newcommand{\norm}[1]{ \left\| #1 \right\|}\newcommand{\prt}{\mathcal{P}}\newcommand{\st}{\text{ such that }}\newcommand{\for}{\text{ for }} \newcommand{\cl}[1]{\text{cl}(#1)}\newcommand{\oiv}[1]{\left] #1 \right[}\newcommand{\interior}[1]{\text{int}(#1)}$$

Project Euler Problem 587::::Gratus' Blog

Project Euler Problem 587

알고리즘 문제풀이/Project Euler 2019. 6. 19. 02:12

와-! 시험 끝났다-!

종강하고 문제 다시 풀기 시작하려고 하는데... 빡센 문제도 풀어봐야겠지만, 역시 랭작하는 재미는 또 다른 얘기니까 

Project Euler에서 쉬운 문제를 하나 먹고 지나가자. 엥간하면 PE는 15% 이상부터는 포스팅을 다 해두려고 한다.

 

https://projecteuler.net/problem=587

 

난이도 : 20%

 

 

문제 설명

 

그림에서, 파란색 영역을 L-section이라고 하자.

그리고, 오른쪽 그림처럼 선을 그었을 때 잘리는 아래 부분(주황색)을 Concave triangle이라고 하자. 

원이 한 개일 때는 그림에서 볼 수 있듯이, Concave Traingle이 L-section의 50% 넓이를 갖는다.

그러나, 원이 2개일 때는 위 그림처럼 넓이의 비율이 50%가 되지 않는다. 실제로 원이 2개일 때는 36.46%이다.

 

원이 $n$개일 때, 처음으로 넓이의 비율 (즉, Concave Triangle / L-section) 이 0.1%보다 작아지는 최초의 $n$을 찾자.

 

 

풀이

처음에 드는 생각은, 이 문제를 어떻게 기하적으로 잘 풀어볼 수 없는가? 하는 것인데, 상당히 불편한 요소가 많아 보인다. (내 기하 실력이 부족해서일 수도 있지만...)

그다음은 해석기하를 도입해 보자. 원의 반지름이 각각 1씩이라고 하면, L-section의 넓이는 $1 - \frac{\pi}{4}$ 임을 알 수 있다. 또한, 원과 직선이 만나는 점을 $(t, \frac{t}{n})$ 이라고 둘 수 있겠다.

원의 방정식은 양함수로 나타낼 수 없지만, 어차피 우리가 필요한 것은 원의 아랫부분이므로  $y = 1-\sqrt{1-(x-1)^2}$ 로 써도 된다.

그러면 결국 우리가 원하는 Concave triangle의 넓이는 

$$\frac{t^2}{2n} + \int_{t}^{1} 1-\sqrt{1-(x-1)^2} \ dx$$

이렇게 쓸 수 있는데... 오른쪽 함수가 적분이 되나? 사실 $\arctan$ 같은걸 잘 써서 $t$를 잘 표현하고 치환적분해도 되긴 될 것 같...기도 한데. 이시점부터 "아 그냥 수치적분 해야겠다" 라는 생각을 했다.

(여담으로, 적분이 되긴 된다.)

아무튼, 저 식을 계산하고 싶지는 않으므로 수치적분을 짜자.

일단 가장 간단한 직사각형 근사 (구분구적법) 을 써본 다음, 안되면 심프슨 공식을 쓰던 가우스 수치적분을 쓰던 할 생각으로 일단 구분구적을 돌리기로 했다. 숫자가 매우 작으므로 파이썬을 쓰자.

 

빠르게 답을 얻기 위해, 필요한 원의 개수를 이분탐색으로 찾을 수 있다. $n$개의 원으로 0.1%보다 작다면, 그보다 많은 원을 놓더라도 0.1%보다 작을 것임이 자명하기 때문이다. 

import time
from math import sqrt, pi

def f(x, n):
	return min(x/n, 1-sqrt(1-(x-1)*(x-1)))

def solve(n):
	step = 1 / 10000
	A = 0
	for i in range(10000):
		u = step * i
		v = step * (i+1)
		tmparea = step * (f(u, n) + f(v, n))/2
		A += tmparea
	return A

def main():
	Lsec = 1-pi/4
	lo = 1
	hi = 100000
	while lo<hi:
		mid = (lo+hi)//2
		ratio = solve(mid)/Lsec*100
		if ratio < 0.1:
			hi = mid
		else:
			lo = mid+1
	print(lo, solve(lo)/Lsec)

if __name__ == "__main__":
	start_time = time.time()
	main()
	print("--- %s seconds ---" % (time.time() - start_time))

 

 

'알고리즘 문제풀이 > Project Euler' 카테고리의 다른 글

Project Euler Problem 577  (0) 2019.08.18
Project Euler 포스팅 시작 + Problem 75  (0) 2019.05.28
admin