λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

🐍 Python/solve-algorithm

μœ ν΄λ¦¬λ“œ ν˜Έμ œλ²•κ³Ό μž¬κ·€ν•¨μˆ˜ : λ°±μ€€ 2609[μ΅œλŒ€κ³΅μ•½μˆ˜μ™€ μ΅œμ†Œκ³΅λ°°μˆ˜] & 파이썬

였늘 μž¬κ·€ ν•¨μˆ˜λ₯Ό κ³΅λΆ€ν•˜λ©΄μ„œ 전에 ν’€μ—ˆλ˜ λ°±μ€€ λ¬Έμ œκ°€ 생각이 λ‚˜μ„œ 같이 μ •λ¦¬ν•΄λ³΄κ³ μž 가지고 μ™”λ‹€.

πŸ” μž¬κ·€ν•¨μˆ˜(Recursion Function)

좜처 : μž¬κ·€ν•¨μˆ˜ μœ„ν‚€ν”Όλ””μ•„
μž¬κ·€ν•¨μˆ˜λ₯Ό λ‚˜νƒ€λ‚΄λŠ” gif

  • μ‰½κ²Œ λ§ν•˜λ©΄, 자기 μžμ‹ μ„ ν˜ΈμΆœν•˜λŠ” ν•¨μˆ˜.
  • μžμ„Έν•œ μ„€λͺ…은 μž¬κ·€ν•¨μˆ˜ μœ„ν‚€ν”Όλ””μ•„ μ°Έκ³ 
  • μˆ˜ν•™μ  귀납법과 λΉ„μŠ·ν•¨
  • μ‹€μ²΄ν•˜μ§€ μ•ŠλŠ” κ°œλ…μ„ μˆ˜ν•™μ  λͺ¨λΈλ‘œ λ§Œλ“€κ³ , κ·Έ μˆ˜ν•™μ  λͺ¨λΈμ„ ν•˜λ‚˜μ”© μ°¨κ°μ‹œμΌœκ°€λ©΄μ„œ ν˜ΈμΆœν•˜λŠ” κ²ƒλ§ŒμœΌλ‘œλ„ λ¬Έμ œκ°€ ν•΄κ²°λ˜κ²Œ ν•˜λŠ” 것

1 ) μž¬κ·€ν•¨μˆ˜μ˜ ν™œμš©

  • μž¬κ·€μ μœΌλ‘œ 문제λ₯Ό ν‘Όλ‹€λŠ” 것 : 같은 ν˜•νƒœμ˜ 더 μž‘μ€ 문제[각주:1]λ₯Ό ν’€κ³ , λΆ€λΆ„ 문제의 닡을 μ΄μš©ν•΄μ„œ κΈ°μ‘΄ 문제λ₯Ό ν‘ΈλŠ” 것!
  • μž¬κ·€μ μœΌλ‘œ ν’€κΈ° μœ„ν•΄μ„œλŠ” 항상 μ•„λž˜μ™€ 같이 두 caseλ₯Ό λ‚˜λˆ„μ–΄μ„œ μƒκ°ν•΄μ•Όν•œλ‹€.
    1. Base case: 이미 λ¬Έμ œκ°€ μΆ©λΆ„νžˆ μž‘μ•„μ„œ, 더 μž‘μ€ λΆ€λΆ„ 문제둜 λ‚˜λˆ„μ§€ μ•Šκ³ λ„ λ°”λ‘œ 닡을 μ•Œ 수 μžˆλŠ” 경우
    2. Recursive case: ν˜„ λ¬Έμ œκ°€ λ„ˆλ¬΄ μ»€μ„œ, 같은 ν˜•νƒœμ˜ 더 μž‘μ€ λΆ€λΆ„ 문제λ₯Ό μž¬κ·€μ μœΌλ‘œ ν‘ΈλŠ” 경우
  • 예제 : νŒ©ν† λ¦¬μ–Ό 문제
'''[νŒ©ν† λ¦¬μ–Ό]'''
# μž¬κ·€μ  풀이
def factorial(n):
	# base case
    if n == 0:
        return 1
    # recursive case
    return factorial(n - 1) * n

print(factorial(3))

# 반볡문 풀이
def factorial_loop(n):
    result = 1
    for i in range(1, n + 1):
        # print(i) # 1, 2, 3
        result *= i
    return result

print(factorial_loop(3))

  

μœ„μ˜ μž¬κ·€ν•¨μˆ˜ 그림으둜 μ΄ν•΄ν•˜κΈ°

 

  

λ©”λͺ¨λ¦¬κ°’κ³Ό 같이 λ³΄λ©΄μ„œ 느껴보기

2) μž¬κ·€ν•¨μˆ˜ vs 반볡문

μœ„μ˜ νŒ©ν† λ¦¬μ–Ό μ˜ˆμ œμ—μ„œλ„ μ•Œ 수 μžˆλ“―, λŒ€λΆ€λΆ„μ˜ μž¬κ·€ν•¨μˆ˜λŠ” 반볡문(iteration, loop)κ³Ό λ³€μˆ˜λ₯Ό μ΄μš©ν•˜λŠ” 반볡적 μ•Œκ³ λ¦¬μ¦˜μœΌλ‘œ κ΅¬ν˜„μ΄ κ°€λŠ₯ν•˜κ³  κ·Έ 역도 μ„±λ¦½ν•œλ‹€.

  • λ°˜λ³΅λ¬Έμ€ μ½”λ“œμ—μ„œ λŒ€λ†“κ³  '이 블둝은 반볡될 κ²ƒμž„'ν•˜κ³  μ•Œλ €μ£ΌλŠ” 것과 λ‹€λ₯΄κ²Œ μž¬κ·€λŠ” 별닀λ₯Έ ν‘œμ‹œ 없이 혼자 돌게 λ˜λ―€λ‘œ μ½”λ“œ λ‚΄μ—μ„œ 가독성이 떨어지고 흐름을 μΆ”μ ν•˜κΈ° μ–΄λ ΅λ‹€.
  • μž¬κ·€μ μœΌλ‘œ λ„ˆλ¬΄ λ§Žμ€ ν•¨μˆ˜ 호좜이 μžˆλŠ” μ•Œκ³ λ¦¬μ¦˜(Call Stack[각주:2]이 많이 μŒ“μ—¬ 였λ₯˜κ°€ λ‚˜λŠ” μ•Œκ³ λ¦¬μ¦˜)일 것 같은 κ²½μš°μ—λŠ” κ³ΌλΆ€ν•˜λ‘œ ν”„λ‘œκ·Έλž¨μ΄ 쀑단 될 수 μžˆλ‹€.(stack overflow) μ΄λŸ¬ν•œ κ²½μš°μ—λŠ” λ°˜λ³΅λ¬Έμ„ μ‚¬μš©ν•˜λŠ” 것을 ꢌμž₯!
  • μž¬κ·€ν•¨μˆ˜ 섀계 μ‹œ, μž…λ ₯값이 μ’…λ£Œ 쑰건으둜 μˆ˜λ ΄ν•˜λŠ”μ§€λ₯Ό κΌ­ 검증해야 ν•œλ‹€.
  • κ·ΈλŸΌμ—λ„ λΆˆκ΅¬ν•˜κ³  μž¬κ·€ν•¨μˆ˜λ₯Ό λ°°μ›Œμ•Ό ν•˜λŠ” μ΄μœ λŠ” λ‹¨μˆœνžˆ 기계적인 μ΅œμ ν™” μˆ˜μ€€μ˜ 이야기λ₯Ό λ„˜μ–΄μ„œ, μ•Œκ³ λ¦¬μ¦˜μ  μΈ‘λ©΄μ—μ„œ 보자면 μž¬κ·€μ  사고방식을 ν‰μ†Œμ— μ—°μŠ΅ν•˜λŠ” 것이 맀우 μ€‘μš”ν•˜κΈ° λ•Œλ¬Έ! μž¬κ·€μ  사고 방식은 ν”νžˆ λ§ν•˜λŠ” 뢄할정볡에 기초λ₯Ό λ‘”λ‹€.
  • μ–΄λ–€ 리슀트의 합을 κ΅¬ν•˜λŠ” 경우λ₯Ό μƒκ°ν•΄λ³΄μž. λ‹¨μˆœνžˆ λͺ…λ Ήν˜• 사고에 μ΅μˆ™ν•΄μ‘Œλ‹€λ©΄ 이λ₯Ό $O(n)$으둜 κ΅¬ν•˜κ³ , κ·Έ 닡에 λ§Œμ‘±ν–ˆμ„ 것이닀. ν•˜μ§€λ§Œ 이 λ¬Έμ œλŠ” μž¬κ·€μ μœΌλ‘œ 생각할 경우 $O(log n)$λ§Œμ— ν•΄κ²°ν•  수 μžˆλ‹€. 이처럼 기계적 μˆ˜μ€€μ˜ μ΅œμ ν™”κ°€ μ•„λ‹ˆλΌ, 더 높은 μˆ˜μ€€μ˜ 생산성과 νš¨μœ¨μ„ μΆ”κ΅¬ν•œλ‹€λ©΄ ν‰μ†Œμ— μž¬κ·€μ μœΌλ‘œ μ‚¬κ³ ν•˜λŠ” μŠ΅κ΄€μ„ λ“€μ—¬μ•Ό ν•œλ‹€! πŸ’ͺ

3) Call Stack 1000개(κΈ°λ³Έ κ°’) μ΄μƒμœΌλ‘œ λŠ˜λ¦¬λŠ” 방법

sys 라이브러리λ₯Ό 톡해 ν˜„μž¬ ν•œκ³„λ₯Ό 좜λ ₯ν•΄μ„œ 확인이 κ°€λŠ₯ν•˜κ³ , 값을 μˆ˜μ •ν•  μˆ˜λ„ μžˆλ‹€. πŸ₯•πŸ‘

import sys

# κΈ°λ³Έ κ°’ : 1000
print(sys.getrecursionlimit())

# ν•œκ³„ 늘리기
sys.setrecursionlimit(3000)

# λŠ˜λ €μ§„ ν•œκ³„ 확인 : 3000
print(sys.getrecursionlimit())

πŸ” μœ ν΄λ¦¬λ“œ ν˜Έμ œλ²•(Euclidean algorithm)

  • 2개의 μžμ—°μˆ˜ λ˜λŠ” 정식[각주:3]의 μ΅œλŒ€κ³΅μ•½μˆ˜(GCD)λ₯Ό κ΅¬ν•˜λŠ” μ•Œκ³ λ¦¬μ¦˜μ˜ ν•˜λ‚˜
  • ν˜Έμ œλ²• : 두 μˆ˜κ°€ μ„œλ‘œ μƒλŒ€λ°© 수λ₯Ό λ‚˜λˆ„μ–΄μ„œ κ²°κ΅­ μ›ν•˜λŠ” 수λ₯Ό μ•Œκ³ λ¦¬μ¦˜μ„ λ§ν•œλ‹€.
  • μœ ν΄λ¦¬λ“œ ν˜Έμ œλ²•μ€ λ‚˜λˆ—μ…ˆλ§Œ λ°˜λ³΅ν•΄μ„œ μ΅œλŒ€κ³΅μ•½μˆ˜λ₯Ό ꡬ할 수 μžˆλ‹€.
  • 두 μˆ˜κ°€ 아무리 컀도 정해진 μˆœμ„œλ‘œ κ³„μ‚°ν•˜λ©΄ 효율적으둜 μ΅œλŒ€κ³΅μ•½μˆ˜λ₯Ό ꡬ할 수 μžˆλ‹€.
  • 방법 : 2개의 μžμ—°μˆ˜ $x, y$에 λŒ€ν•΄μ„œ $x$λ₯Ό $y$둜 λ‚˜λˆˆ λ‚˜λ¨Έμ§€λ₯Ό $r$이라고 ν•˜λ©΄, $x$와 $y$의 μ΅œλŒ€κ³΅μ•½μˆ˜λŠ” $y$와 $r$의 μ΅œλŒ€κ³΅μ•½μˆ˜μ™€ κ°™λ‹€. 이 μ„±μ§ˆμ— 따라, $y$λ₯Ό $r$둜 λ‚˜λˆˆ λ‚˜λ¨Έμ§€ $r'$λ₯Ό κ΅¬ν•˜κ³  λ‹€μ‹œ $r$을 $r'$둜 λ‚˜λˆˆ λ‚˜λ¨Έμ§€λ₯Ό κ΅¬ν•˜λŠ” 과정을 λ°˜λ³΅ν•˜μ—¬ λ‚˜λ¨Έμ§€κ°€ 0이 λ˜μ—ˆμ„ λ•Œ λ‚˜λˆ„λŠ” μˆ˜κ°€ $x$와 $y$의 μ΅œλŒ€κ³΅μ•½μˆ˜μ΄λ‹€.
  • μ˜ˆμ‹œλ₯Ό 보면 이해가 λΉ λ₯΄λ‹€.
    • 19와 7의 μ΅œλŒ€κ³΅μ•½μˆ˜λ₯Ό κ΅¬ν•΄λ³΄μž
    • 19와 7의 μ΅œλŒ€κ³΅μ•½μˆ˜λŠ” 7와 5의 μ΅œλŒ€κ³΅μ•½μˆ˜μ™€ κ°™λ‹€. 이 μ„±μ§ˆμ— 따라, 7λ₯Ό 5둜 λ‚˜λˆˆ λ‚˜λ¨Έμ§€ 2λ₯Ό κ΅¬ν•˜κ³  λ‹€μ‹œ 5을 2둜 λ‚˜λˆˆ λ‚˜λ¨Έμ§€λ₯Ό κ΅¬ν•˜λŠ” 과정을 λ°˜λ³΅ν•˜μ—¬ λ‚˜λ¨Έμ§€κ°€ 0이 λ˜μ—ˆμ„ λ•Œ λ‚˜λˆ„λŠ” 수인 1이 19와 7의 μ΅œλŒ€κ³΅μ•½μˆ˜μ΄λ‹€.
19 = 7x2 + 5
7 = 5x1 + 2
5 = 2x2 + 1
2 = 1X2 + 0

λ°±μ€€ 2609 [μ΅œλŒ€κ³΅μ•½μˆ˜μ™€ μ΅œμ†Œκ³΅λ°°μˆ˜]

πŸ“Ž Problem

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

 

2609번: μ΅œλŒ€κ³΅μ•½μˆ˜μ™€ μ΅œμ†Œκ³΅λ°°μˆ˜

첫째 μ€„μ—λŠ” μž…λ ₯으둜 주어진 두 수의 μ΅œλŒ€κ³΅μ•½μˆ˜λ₯Ό, λ‘˜μ§Έ μ€„μ—λŠ” μž…λ ₯으둜 주어진 두 수의 μ΅œμ†Œ 곡배수λ₯Ό 좜λ ₯ν•œλ‹€.

www.acmicpc.net

πŸ“Ž Note

  • κ³΅μ•½μˆ˜ : 두 수 μ‚¬μ΄μ—μ„œ κ³΅ν†΅μœΌλ‘œ μ‘΄μž¬ν•˜λŠ” μ•½μˆ˜
  • μ΅œλŒ€κ³΅μ•½μˆ˜(GCD, Greate Common Divisor) : κ³΅μ•½μˆ˜ 쀑에 κ°€μž₯ 큰 κ³΅μ•½μˆ˜
  • 곡배수 : 두 수의 곡톡적인 배수
  • μ΅œμ†Œκ³΅λ°°μˆ˜(LCM, Least Common Multiple) : 곡배수 쀑에 제일 μž‘μ€ 곡배수
'''
πŸ’» code
1. gcd(a, b)
    κ³„μ†ν•΄μ„œ aλ₯Ό b둜 λ‚˜λˆ„μ–΄μ„œ bλ₯Ό a에 λ‚˜λˆˆ λ‚˜λ¨Έμ§€ bλ₯Ό λŒ€μž…μ‹œμΌœμ„œ bκ°€ 0이 λ λ•ŒκΉŒμ§€ λ°˜λ³΅ν•˜λ©΄
    λ‚¨λŠ” a의 값이 μ΅œλŒ€κ³΅μ•½μˆ˜κ°€ λœλ‹€

def gcd(a, b):
    while b > 0:
    a, b = b, a % b
return a


2. lcm(a, b)
    a, b의 곱을 a, b의 μ΅œλŒ€κ³΅μ•½μˆ˜λ‘œ λ‚˜λˆˆ 값이닀.(λͺ« : //)

gcd * lcm= num1 * num2


def lcm(a, b):
    return a * b // gcd(a, b)
'''

πŸ“Ž Submission Code

# case 1 : 이미 κ΅¬ν˜„μ΄ λ˜μ–΄μžˆλŠ” math λͺ¨λ“ˆμ„ μž„ν¬νŠΈν•΄μ„œ μ‚¬μš©ν•  수 μžˆλ‹€.
import math

num1, num2 = map(int, input().split())

print(math.gcd(num1, num2))
print(math.lcm(num1, num2))

# case 2 : μœ ν΄λ¦¬λ“œ ν˜Έμ œλ²•
num1, num2 = map(int, input().split())

def gcd(num1, num2):
    while num2 > 0:
        num1, num2 = num2, num1 % num2
    return num1

def lcm(num1, num2):
    return num1 * num2 // gcd(num1, num2)

print(gcd(num1, num2))
print(lcm(num1, num2))

πŸ“Ž μž¬κ·€ν•¨μˆ˜μ™€ μ΅œμ†Œκ³΅μ•½μˆ˜

def factor(num1, num2):
    # μœ ν΄λ¦¬λ“œ ν˜Έμ œλ²•
    remain = num1 % num2
    # check
    print(f"num1: {num1}, num2: {num2}, λ‚˜λ¨Έμ§€ : {remain}")

    # base case
    if remain == 0:
        return num2

    # recursive case
    return factor(num2, remain)
    
'''
좜λ ₯ : 
num1: 7, num2: 19, λ‚˜λ¨Έμ§€ : 7
num1: 19, num2: 7, λ‚˜λ¨Έμ§€ : 5
num1: 7, num2: 5, λ‚˜λ¨Έμ§€ : 2
num1: 5, num2: 2, λ‚˜λ¨Έμ§€ : 1
num1: 2, num2: 1, λ‚˜λ¨Έμ§€ : 0
1
'''

πŸ“Ž Reference

 

 

 

 

  1. (= λΆ€λΆ„ 문제, Subproblem) [본문으둜]
  2. 콜 μŠ€νƒ μ΄λž€ 컴퓨터 ν”„λ‘œκ·Έλž¨μ—μ„œ ν˜„μž¬ μ‹€ν–‰ 쀑인 μ„œλΈŒλ£¨ν‹΄μ— κ΄€ν•œ 정보λ₯Ό μ €μž₯ν•˜λŠ” μŠ€νƒ μžλ£Œκ΅¬μ‘°μ΄λ‹€. [본문으둜]
  3. γ€Šμˆ˜ν•™γ€‹ λ¬Έμžκ°€ λ“  μ‹μœΌλ‘œ, λ”ν•˜κΈ°, λΉΌκΈ°, κ³±ν•˜κΈ°μ— ν•œν•˜κ³ , λ‚˜λˆ„λŠ” 일이 μ—†λŠ” μœ λ¦¬μ‹.  [본문으둜]