4/9 파이썬 수학 알고리즘

JK·2023년 4월 11일

알고리즘 문제를 풀며 생각보다 수학적 지식이 필요한 문제가 많다고 생각했습니다
오늘은 대표적인 수학적 지식이 필요한 알고리즘을 공부하며 문제를 풀어보았습니다

최대공약수, 최소공배수

최대공약수

def solution(a, b):
    min_num = a if a < b else b
    for i in range(min_num, 0, -1):
        if a % i == 0 and b % i == 0:
            answer = i
            break
    return answer

최소공배수

1.
def solution(a, b):
    max_num = a if a > b else b
    for i in range(max_num, a * b + 1):
        if i % a == 0 and i % b == 0:
            answer = i
            break
    return print(answer)
2.
def solution(a, b):
    min_num = a if a < b else b
    for i in range(1, min_num + 1):
        if not (a * i) % b:
            answer = a * i
            break
    return print(answer)

거듭제곱근 구하기

16의 거듭제곱근은 (2 이상): 2 4, 4 2.
이때 제곱근 구하는 식
n ** (1.00 / 실수형 숫자)
실수형: float(숫자)
n = int(input())

for i in range(2, n + 1):
    if not n ** (1.00 / float(i)) % 2:
        print(int(n ** (1.00 / float(i))), i)

약수의 개수 판별하기

if int(n ** 0.5) == n ** 0.5:
	print('약수의 개수가 홀수 입니다')
else:
	print('약수의 개수가 짝수 입니다')
: 제곱수이면, 약수의 개수는 홀수이다.

소수 구하기

소수 판별하기

기본적인 방법
def is_prime_num(n):
    for i in range(2, n):
        if n % i == 0:
            return False # 소수가 아님
    return True # 소수

조금 더 빠른 방법: 약수 이용하기

아이디어: 어떤 수의 제곱근을 기준으로 약수들이 서로 대칭됨을 이용하자.
제곱근의 왼쪽에 약수가 없다면, 오른쪽에도 없을 것이다.

def is_prime_num(n):
    for i in range(2, int(n**(1/2))+1): # n의 제곱근(정수화함) + 1 범위까지
        if n % i == 0:
            return False # 소수가 아님
    return True # 소수

특정 숫자까지의 수 중에서 소수 구하기

소요 시간 비교해보기

  1. 이중 for문
n = int(input())
prime_num = []

for i in range(2, n + 1):
    prime = True
    for j in range(2, i):
        if i % j == 0:
            prime = False
            break
    if prime:
        prime_num.append(i)

print(prime_num)
  1. 에라토스테네스의 체 (훨씬 빠름!)

2 ~ N까지의 범위가 담긴 배열을 만든다.
해당 배열 내의 가장 작은 수 i 부터 시작하여, i의 배수들을 해당 배열에서 지워준다. (i는 소수이기 때문에 i자체는 지우지 않는다.)
주어진 범위 내에서 i의 배수가 모두 지워지면 i 다음으로 작은 수의 배수를 같은 방식으로 배열에서 지워준다.
더 이상 반복할 수 없을 때까지 2, 3번의 과정을 반복해준다.

  1. 배수가 아닌 수를 리스트에 추가하며..: 더 비효율적인가? 시간 체크하기!
prime_num = list(range(2, n + 1))
n_cnt_all = [] # 소수가 아닌 수를 담을 list

for num in range(2, n + 1):
    if not num in n_cnt_all: 
        n_cnt = [] # 초기화
        
        for cnt in range(2, n + 1):
            num_cnt = num * cnt # 배수 찾기
            
            if num_cnt in prime_num:
                n_cnt.append(num_cnt)
                
        n_cnt_all.append(n_cnt)
        # 배수인 수를 제외한 수만 담음
        prime_num = [i for i in prime_num if i not in n_cnt]
      
print(prime_num)'

중복 계산을 피하기 위해 if num_cnt in prime_num: 추가

  1. 특정 수가 지워졌는지 확인하며..(좀 더 효율적)
def is_prime_num(n):
    arr = [True] * (n + 1) # 특정 수가 지워졌는지 아닌지 확인하기 위한 배열
    arr[0], arr[1] = False, False

    for i in range(2, n + 1):
        if arr[i] == True: # 특정 수가 지워지지 않았다면 (소수여서)
            j = 2

            while (i * j) <= n:
                arr[i*j] = False # i의 배수의 값을 False로 지워준다.
                j += 1

    return arr

prime_num = []

arr = is_prime_num(100) # 0 ~ 50중 소수를 구하기 위한 함수

for i in range(len(arr)):
    if arr[i] == True:
        prime_num.append(i)
print(prime_num)

출처: 소수판별 알고리즘 - 파이썬 (Python)
가장 긴 증가하는 부분 수열(LIS)
오름차순 일 때

arr 5 20 10 40 30 50 60
dp 1 2 2 3 3 4 5

정렬하면

arr 5 10 20 30 40 50 60

내림차순 일 때

arr 60 50 30 10 40 20 5 70
dp 1 2 3 2 3 4 5 1

정렬하면

arr 70 60 50 40 30 20 10 5

응용 문제 :

문제 링크

골드바흐의 추측 - 9020

성능 요약
메모리: 31256 KB, 시간: 620 ms

분류
수학, 정수론, 소수 판정, 에라토스테네스의 체

문제 설명
1보다 큰 자연수 중에서 1과 자기 자신을 제외한 약수가 없는 자연수를 소수라고 한다. 예를 들어, 5는 1과 5를 제외한 약수가 없기 때문에 소수이다. 하지만, 6은 6 = 2 × 3 이기 때문에 소수가 아니다.
골드바흐의 추측은 유명한 정수론의 미해결 문제로, 2보다 큰 모든 짝수는 두 소수의 합으로 나타낼 수 있다는 것이다. 이러한 수를 골드바흐 수라고 한다. 또, 짝수를 두 소수의 합으로 나타내는 표현을 그 수의 골드바흐 파티션이라고 한다. 예를 들면, 4 = 2 + 2, 6 = 3 + 3, 8 = 3 + 5, 10 = 5 + 5, 12 = 5 + 7, 14 = 3 + 11, 14 = 7 + 7이다. 10000보다 작거나 같은 모든 짝수 n에 대한 골드바흐 파티션은 존재한다.
2보다 큰 짝수 n이 주어졌을 때, n의 골드바흐 파티션을 출력하는 프로그램을 작성하시오. 만약 가능한 n의 골드바흐 파티션이 여러 가지인 경우에는 두 소수의 차이가 가장 작은 것을 출력한다.

입력
첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고 짝수 n이 주어진다.

출력
각 테스트 케이스에 대해서 주어진 n의 골드바흐 파티션을 출력한다. 출력하는 소수는 작은 것부터 먼저 출력하며, 공백으로 구분한다.

def prime(n):
    if n == 1:
        return False
    for i in range(2, int(n**0.5) + 1):
        if n % i == 0:
            return False
    return True

t = int(input())
for _ in range(t):
    num = int(input())
    num1 = num // 2
    num2 = num // 2
    while True:
        if num1 == 0:
            break
        if prime(num1) and prime(num2):
            print(num1, num2)
            break
        else:
            num1 -= 1
            num2 += 1코드를 입력하세요

문제 링크

달팽이는 올라가고 싶다 - 2869

성능 요약
메모리: 33376KB, 시간: 44ms

분류
수학

문제 설명
땅 위에 있다가 있다. 이 부분은 높이가 V미터인 나무 막대를 배관해야 합니다.
오후는 낮에 A미터가 될 수 있다. 하지만, 밤에 잠을 자는 동안 B미터가 작아진다. 또, 정상에 가까워지면 나중에는 지지 않는다.
건전지가 나무 막대를 모두 보이게 하려면, 배수가 펴지 구하는 프로그램을 작성하시오.
엔터
항상 줄에 세 정수 A, B, V가 공백으로 구분하여 주어다. (1 ≤ B < A ≤ V ≤ 1,000,000,000)
최고
지속적으로 늘어놓을 때마다 나무를 모두 놓았는데요.

import math

a, b, v = map(int, input().split())

day = (v-b)/(a-b)
print(math.ceil(day))
profile
^^

0개의 댓글