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

 

6588번: 골드바흐의 추측

각 테스트 케이스에 대해서, n = a + b 형태로 출력한다. 이때, a와 b는 홀수 소수이다. 숫자와 연산자는 공백 하나로 구분되어져 있다. 만약, n을 만들 수 있는 방법이 여러 가지라면, b-a가 가장 큰

www.acmicpc.net

 

문제

골드바흐의 추측 : 4보다 큰 모든 짝수는 두 홀수 소수의 합으로 나타낼 수 있다.

 

백만 이하의 짝수를 받으면, 해당 짝수를 두 홀수 소수의 합으로 표현하는 문제입니다.

아직 해결되지 않았다 했으므로, 나타낼 수 없는 경우를 작성하지 않았습니다.

 

풀이

에라토스테네스의 체를 통해, 백만 이하의 소수를 구합니다.

그리고, 2를 제외한 소수는 모두 홀수이므로 3부터 시작해서 더해서 원하는 짝수가 나오는 홀수 두 개를 찾습니다.

 

LIMIT = 1000001
prime_list = [True] * (LIMIT)

for i in range(2,1001):
    if prime_list[i]:
        for j in range(2*i,LIMIT, i):
            prime_list[j] = False


while True:
    x = int(input())
    if(x==0): break

    for i in range(3,LIMIT):
        if prime_list[i] and prime_list[x-i]:
            print(x, '=', i, '+' , x-i)
            break

 

에라토스테네스의 체

: 해당 수보다 작은 모든 수로 나누어 보아서 소수인지 확인하는 방법입니다.

 

1. 1은 제거

2. 지워지지 않은 수 중 제일 작은 2를 채택하고, 나머지 2의 배수를 지웁니다.

3. 지워지지 않은 수 중 제일 작은 3을 채택하고, 나머지 3의 배수를 모두 지웁니다.

4. 지워지지 않은 수 중 제일 작은 5를 채택하고, 나머지 5의 배수를 모두 지웁니다.

 

다음과 같은 과정을 반복합니다.

 

에라토스테네스의 체

n=1000
a = [False,False] + [True]*(n-1)
primes=[]

for i in range(2,n+1):
  if a[i]:
    primes.append(i)
    for j in range(2*i, n+1, i):
        a[j] = False
print(primes)

https://wikidocs.net/21638

 

2. 소수 구하기 - 에라토스테네스의 체

# 소수 : 1과 그 수 자신 이외의 자연수로는 나눌 수 없는 자연수이다. # 코딩 소수인지 검사하는 함수(isPrime)를 만든다. 1부터 100 사이의 소수를 구하는 ...

wikidocs.net

 

'알고리즘 공부 > 수학' 카테고리의 다른 글

[백준/수학] 4375번: 1  (0) 2022.10.02
[백준/수학] 1094번: 막대기  (1) 2022.10.02
[백준/수학] 11689번: GCD(n,k)=1  (0) 2022.09.18
[백준/기하학] 11758번 CCW  (0) 2022.08.21
[백준/수학] 3360번 깡총깡총  (0) 2022.03.18

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

 

10797번: 10부제

서울시는 6월 1일부터 교통 혼잡을 막기 위해서 자동차 10부제를 시행한다. 자동차 10부제는 자동차 번호의 일의 자리 숫자와 날짜의 일의 자리 숫자가 일치하면 해당 자동차의 운행을 금지하는

www.acmicpc.net

 

문제에서 날짜의 일의 자리수, 자동차 번호의 일의 자리 수들을 제공하기 때문에,

자동차 번호들에서 날짜의 일의 자리수가 몇 개인지를 세어주면 됩니다.

 

num = int(input())
cars_num = list(map(int,input().split()))
print(cars_num.count(num))

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

 

1094번: 막대기

지민이는 길이가 64cm인 막대를 가지고 있다. 어느 날, 그는 길이가 Xcm인 막대가 가지고 싶어졌다. 지민이는 원래 가지고 있던 막대를 더 작은 막대로 자른다음에, 풀로 붙여서 길이가 Xcm인 막대

www.acmicpc.net

문제

지민이가 원하는 X cm 길이의 막대기를 만드려고 하는데,

이 때, 64cm 막대기부터 시작해서 막대기를 반 씩 잘라서 만드는 과정을 몇 번 반복하면 되는가 하는 문제입니다.

 

풀이

64cm를 반 씩 자르면, 나올 수 있는 길이는 1, 2, 4, 8, 16, 32, 64입니다.

결국에는 이진법으로 나타냈을 때 1이 몇개 있는지 묻는 문제입니다.

 

48 = 0110000(2)

 

X=int(input())
count = 0

while X!=0:
    if X%2==1:
        count+=1
    X=X//2
print(count)

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

 

1476번: 날짜 계산

준규가 사는 나라는 우리가 사용하는 연도와 다른 방식을 이용한다. 준규가 사는 나라에서는 수 3개를 이용해서 연도를 나타낸다. 각각의 수는 지구, 태양, 그리고 달을 나타낸다. 지구를 나타

www.acmicpc.net

 

E, S, M 에 해당하는 범위가 다르므로,

브루트 포스를 사용하여 연도에서 주어진 E, S, M 을 뺐을 때 나머지가 0인 연도를 찾는 문제입니다.

 

E,S,M = map(int,input().split())

year = 1

while True:
    if(year-E)%15==0 and (year-S)%28==0 and (year-M)%19==0:
        break
    year += 1
print(year)

 

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

 

11689번: GCD(n, k) = 1

자연수 n이 주어졌을 때, GCD(n, k) = 1을 만족하는 자연수 1 ≤ k ≤ n 의 개수를 구하는 프로그램을 작성하시오.

www.acmicpc.net

 

GCD(Greatest Common Divisor)은 최대 공약수를 의미합니다.

문제에서 최대 공약수가 1인 k의 개수를 구하라는 의미는, n의 서로소를 구하라는 뜻입니다.

서로소의 개수를 구하는 함수는 오일러 파이 함수가 있습니다.

 

오일러 파이 함수란?

임의의 양의 정수 m에 대하여, m 이하의 양의 정수 중 m과 서로송인 양의 정소의 개수를 구하는 함수입니다.

$$p_1, p_2, ..., p_n$$이 m의 소인수라고 할 때 아래 공식이 성립하게 됩니다.

 

오일러 파이 함수 식에 대한 증명

 

\(p\)가 소수라면, 1부터 \(p^k\) 까지의 수 중 \(p\)를 인수로 가지는 숫자의 개수는 \(p^{k-1}\)입니다.

그러므로 

$$\Phi(p^k)=p^k - p^{(k-1)}$$

식이 성립됩니다.

 

그러므로 만약 a가 다음과 같이 정의된다면, 아래의 식으로 나타낼 수 있습니다.

 

이제 파이썬으로 나타내면 다음과 같습니다.

n = int(input())
answer=n
for i in range(2, round(n**0.5) + 1):
    #소인수 이면
    if n%i==0:
        #소인수 구하기
        while n%i==0:
            n//=i
        #(1-(1/i))
        answer*=((i-1)/i)
if n>1:
    answer*=1-(1/n)
print(int(answer))

 

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

 

1292번: 쉽게 푸는 문제

첫째 줄에 구간의 시작과 끝을 나타내는 정수 A, B(1 ≤ A ≤ B ≤ 1,000)가 주어진다. 즉, 수열에서 A번째 숫자부터 B번째 숫자까지 합을 구하면 된다.

www.acmicpc.net

 

문제 상황

1이 한개, 2가 2개, 3이 3개 ... N이 N개가 있는 수열이 있습니다.

이 수열에서 시작과 끝을 나타내는 정수가 주어졌을 때, 그 일정한 구간의 합을 구하는 문제입니다.

 

해결 방법

위의 수열을 직접 만드는 방법을 선택했습니다.

현재 문제에서 끝은 1000까지로 제한되어있으므로, 46까지 있는 수열을 만들면 됩니다.

그래서 이중 반복문을 사용하여, 직접 수열을 만들었습니다.

 

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

arr = [0]

for i in range(46):
    for j in range(i):
        arr.append(i)

print(sum(arr[a:b+1]))

동기와 비동기에 대해 알아봅시다.

동기(synchronous: 동시에 일어나는)

  • 요청과 결과가 동시에 일어난다는 약속으로, 요청을 하면 요청한 자리에서 결과가 주어져야 합니다.
  • 장점 : 일의 순서가 매우 직관적이고 간단합니다.
  • 단점 : 앞의 일이 오래걸리더라도 뒤의 일은 대기해야합니다.

비동기(asynchronous: 동시에 일어나지 않는)

  • 요청한 자리에서 결과가 주어지지 않습니다.
  • 장점 : 앞의 일이 오래걸리면, 그 시간 동안 다른 작업을 할 수 있습니다. 즉, 자원을 효율적으로 사용할 수 있습니다.
  • 단점 : 일의 순서를 직관적으로 생각하기 어려워서, 무엇이 먼저 완료될지 보장할 수 없습니다.

그렇다면, 비동기에서도 순서가 반드시 지켜져야할 때는 어떻게 해야할까요?

예를 들어, 서버에서 데이터를 가져와서 사용할 때는 반드시 데이터를 작업을 끝내야 합니다.

이를 위해 Promise를 사용합니다.

Promise

Promise는 Javascript 비동기 처리에 쓰이는 객체입니다.

비동기 작업의 결과인 미래의 완료 또는 실패와 그 결과 값을 나타냅니다.

이것을 사용하면 비동기 메서드에서 마치 동기 메서드처럼 값을 반환할 수 있습니다.

다만 원하는 최종 결과를 반환하는 것이 아닌, 미래의 어떤 시점에 결과를 제공하겠다는 약속을 반환합니다.

Promise의 값은 다음 중 하나의 상태를 가집니다.

  • 대기(pending) : 이행하지도, 거부하지도 않은 초기 상태
  • 이행(fulfilled) : 연산이 성공적으로 완료됨.
  • 거부(rejected) : 연산이 실패함.

 

이행이나 거부될 때, 프로미스의 then 메서드에 의해 대기열(큐)에 추가된 처리기들이 호출됩니다.

Promise를 통해 약속을 받는 것은 알겠지만, 그러면 약속 안의 결과값을 받으려면 어떻게 해야할까요?

이를 위해 await을 사용합니다.

 

 

Await

await 연산자는 Promise를 기다리기 위해 사용됩니다.

연산자는 반드시 async function 내부에서만 사용할 수 있습니다. asnyc 함수의 본문 외부에서 사용하면 SyntaxError 가 발생합니다.

async가 무엇인지는 await을 설명 후 설명하겠습니다.

await은 다음과 같이 사용할 수 있습니다.

[rv] = await expression;
  • expression : Promise 혹은 기다릴 어떤 값입니다.
  • rv : Promise에 의해 만족되는 값이 반환됩니다. Promise가 아닌 경우에는 그 값 자체가 반환됩니다.

await 문은 Promise가 이행(fulfill)되거나 거부(reject) 될 때까지 async function 의 실행을 일시 정지합니다.

Promise가 이행(fulfill)되면 async function 를 일시 정지한 부분부터 실행합니다.

이때 await 문의 반환값은 Promise 에서 이행(fulfill)된 값이 됩니다.

만약 Promise가 거부(reject)되면, await 문은 거부(reject)된 값을 throw합니다.

 

 

예제

만약 Promiseawait에 넘겨지면, awaitPromise가 fulfill되기를 기다렸다가, 해당 값을 리턴합니다.

function resolveAfter2Seconds(x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}

async function f1() {
  var x = await resolveAfter2Seconds(10);
  console.log(x); // 10
}

f1();

만약 값이 Promise가 아니라면, 해당 값은 resolvePromise로 변환되며 이를 기다립니다.

async function f2() {
  var y = await 20;
  console.log(y); // 20
}
f2();

만약 Promise가 reject되면, reject된 값이 throw됩니다.

async function f3() {
  try {
    var z = await Promise.reject(30);
  } catch(e) {
    console.log(e); // 30
  }
}
f3();

try블럭 없이 rejected Promise다루기

    var response = await promisedFunction().catch((err) => { console.error(err); });
    // response will be undefined if the promise is rejected

 

Async function

Async Function 객체를 반환하는 하나의 비동기 함수를 선언합니다.

비동기 함수는 이벤트 루프를 통해 비동기적으로 작도아는 함수로, 암시적으로 Promise를 사용하여 결과 값을 반환합니다.

 

구문

    async function name([param[, param[, ... param]]]) {
        statements
    }

name: 함수 이름

async함수는 항상 promise를 반환합니다.

만약 async함수의 반환값이 명시적으로 promise가 아니라면 암묵적으로 promise로 감쌉니다.

 

 

예시. 위와 아래의 코드는 같은 내용입니다.

    async function foo() {
        return 1
    }
    function foo() {
        return Promise.resolve(1)
    }

 

 

추가적인 내용

  • async/await 함수의 목적은 사용하는 여러 promise의 동작을 동기스럽게 사용할 수 있게 하고, 어떠한 동작을 여러 promise의 그룹에서 간단하게 동작하게 하는 것입니다. promise가 구조화된 callback과 유사한 것 처럼 async/await 또한 제네레이터(generator)와 프로미스(promise)를 묶는것과 유사합니다.
  • awaitPromise...then은 다른 것입니다.
    두 개 이상의 Promise를 동시에 기다리고 싶다면, Promise...then을 통해 병렬적으로 수행할 수 있습니다.

 

개념을 제대로 알지 못한 상태에서 비동기를 사용하면서 발생한 문제들

  • Promise{<pending>} 값을 반환될 때가 있었습니다.
    이유 : async 함수는 return이 promise가 아니어도, 암묵적으로 promise로 감싸기 때문이었습니다.
    해결 : 해당 함수를 사용하기 위해서는 await 함수() 의 형태를 사용해야 합니다.
  • 많은 Promise 값을 전부 기다려야할 때가 있었습니다.
    해결 : Promise.all()을 사용하여, 순회 가능한 객체에 주어진 모든 프로미스가 이행한 후, 혹은 프로미스가 주어지지 않았을 때 이행하는 프로미스를 반환합니다.
    이 때, 프로미스 중 하나라도 거부당하면 Promise.all()은 즉시 거부합니다.
    자세한 내용은 해당 Promise.all() 페이지를 참고해주시기 바랍니다.

 

 

[출처] 해당 링크에 더 자세한 설명이 나와있습니다. 참고하시면 좋을 듯 합니다.

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise

 

Promise - JavaScript | MDN

Promise 객체는 비동기 작업이 맞이할 미래의 완료 또는 실패와 그 결과 값을 나타냅니다.

developer.mozilla.org

 

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/await

 

await - JavaScript | MDN

Promise 혹은 기다릴 어떤 값입니다.

developer.mozilla.org

 

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/async_function

 

async function - JavaScript | MDN

async function 선언은 AsyncFunction객체를 반환하는 하나의 비동기 함수를 정의합니다. 비동기 함수는 이벤트 루프를 통해 비동기적으로 작동하는 함수로, 암시적으로 Promise를 사용하여 결과를 반환

developer.mozilla.org

 

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

 

11000번: 강의실 배정

첫 번째 줄에 N이 주어진다. (1 ≤ N ≤ 200,000) 이후 N개의 줄에 Si, Ti가 주어진다. (0 ≤ Si < Ti ≤ 109)

www.acmicpc.net

 

문제 정의

수업들의 (시작하는 시간, 끝나는 시간) 을 확인하여, 필요한 강의실을 구하는 문제입니다.

 

풀이 방법

  1. 수업 시간을 시작하는 시간을 기준으로 정렬을 합니다.
  2. 첫 수업은 반드시 방이 필요하므로, 방에 수업을 추가합니다.
  3. 이 때, 방에 들어간 수업의 시작 시간은 뒤에 수업들에게 필요하지 않고, 수업의 끝나는 시간이 필요합니다.
    그래서 수업시간의 끝나는 시간을 방에 대한 정보로 저장합니다.
  4. 반복문으로  수업을 확인하면서 수업시간의 시작하는 시간보다, 방의 끝나는 시간보다 빠를 때는 방을 추가합니다.
  5. 아니라면 방의 끝나는 시간을 해당 수업의 끝나는 시간으로 수정합니다.

이 때, 방은 min heap으로 되어있어서, 끝나는 시간은 가장 빠른 것이 나오게 됩니다.

import heapq

N = int(input())
classTime = [tuple(map(int,input().split())) for _ in range(N)] 
classTime.sort()

Room = []
# 끝나는 시간을 Room에 추가합니다.
heapq.heappush(Room, classTime[0][1])

for i in range(1,N):
    # 시작하는 시간이 끝나는 시간보다 빠를 경우
    if classTime[i][0] < Room[0]:
        # Room 추가
        heapq.heappush(Room, classTime[i][1])
    else:
        heapq.heappop(Room)
        heapq.heappush(Room,classTime[i][1])

print(len(Room))

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

 

1662번: 압축

압축되지 않은 문자열 S가 주어졌을 때, 이 문자열중 어떤 부분 문자열은 K(Q)와 같이 압축 할 수 있다. K는 한자리 정수이고, Q는 0자리 이상의 문자열이다. 이 Q라는 문자열이 K번 반복된다는 뜻이

www.acmicpc.net

 

문제 상황

K를 한자리 정수라고하고, Q를 0자리 이상의 문자열이라고 합니다.

K(Q)는 Q의 문자열이 K개가 중복된 것을 의미합니다.

예를 들어 12(34) 라면, 이 문자는 13434를 의미하는 것입니다.

 

이렇게 압축되어 있는 문자열을 풀어서, 문자열의 길이를 구하는 문제입니다.

 

풀이 방법

재귀에 속하는 문제이므로 재귀를 사용하려 했으나, 다음과 같이 문자열을 모두 저장하였더니 메모리 초과가 났습니다.

 

  1. 문자열을 받아서, 반복문으로 문자를 하나씩 확인합니다.
  2. 숫자이면 스택에 저장합니다.
  3. 괄호가 열리면, 스택에 가장 마지막에 있는 문자 k 을 가져옵니다. 
    그리고 괄호 뒤에 있는 문자열부터 함수에 집어넣어서 괄호 안에 있는 문자열 subString을 가져옵니다.
    스택에 N * subString 의 문자열을 넣습니다.
  4. 괄호가 닫히면, 스택에 있는 문자열을 return 해줍니다.

이미 봤던 문자열을 처리하는 방법에서는 재귀함수 안의 반복문에서 사용하는 index를 넘겨주는 방식을 사용했습니다.

import sys
from collections import deque


def PressNumber(string):
    stack = deque([])

    i = 0
    while i < len(string):
        if string[i]=='(':
            k = stack.pop()
            num, subString =  PressNumber(string[i+1:])
            subInt = list(int(k)* subString)
            stack += subInt
            i += num
            i+=1
        elif string[i] == ')':
            subString = ''.join(stack).strip()
            return i+1, subString
        else:
            stack.append(string[i])
            i += 1
    return 0, ''.join(stack)



input = sys.stdin.readline
num, string = PressNumber(input().strip())
print(len(string.strip()))

 

그래서 재귀를 사용하면서, 위에 처럼 문자 자체를 저장하지 않고 문자열의 길이를 반환하는 재귀를 만들었습니다.

또한, 이미 봤던 문자열에 대해서는 전역변수처럼 배열을 사용하여 처리해 주었더니, 간단한 코드가 되었습니다.

import sys

check = [False] * 50

def PressNumber(idx):
    temp = ''
    count = 0
    for i in range(idx,len(string)):
        s = string[i]
        if(check[i]):
            continue

        check[i] = True
        if(s.isdigit()):
            temp = s
            count += 1
        elif(s == '('):
            subString = string[i+1:]
            subCount = PressNumber(idx+1)
            count = count - 1 + int(temp) * subCount
        else:
            return count
    
    return count

input = sys.stdin.readline
string = input().strip()

print(PressNumber(0))

 

다음은 재귀를 사용하지 않고, stack 을 사용하여 만들었습니다.

import sys
from collections import deque

input = sys.stdin.readline

count = 0
temp = ''

string = input().strip()
stack = deque([])
for i in range(len(string)):
    s = string[i]
    if s.isdigit():
        count += 1
        temp = s
    elif s == '(':
        stack.append((temp, count-1))
        count = 0
    else:
        num, beforeString = stack.pop()
        count = int(num) * count + beforeString

print(count)

 

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

 

2212번: 센서

첫째 줄에 센서의 개수 N(1 ≤ N ≤ 10,000), 둘째 줄에 집중국의 개수 K(1 ≤ K ≤ 1000)가 주어진다. 셋째 줄에는 N개의 센서의 좌표가 한 개의 정수로 N개 주어진다. 각 좌표 사이에는 빈 칸이 하나 있

www.acmicpc.net

 

목표 : n개의 센서들을 k개의 구간으로 나눕니다.

 

0. 집중국의 개수가 더 많으면, 센서마다 집중국을 설치하면 되므로 0 입니다.

1. 오름차순으로 센서 위치를 정렬합니다.

2. 센서 사이의 거리를 구하고, 내림차순으로 정렬합니다.

3. 거리 합이 최소인 k구간으로 나누기 위해,거리로 정렬한 것에서 k-1번째의 거리들을 사용합니다. 

 

import sys

input = sys.stdin.readline

n = int(input())
k = int(input())
sensorPoint = sorted(list(map(int,input().split())))

if k>=n:
    print(0)
    sys.exit()

dist = []
for i in range(1,n):
    dist.append(sensorPoint[i] - sensorPoint[i-1])
dist.sort(reverse=True)
print(sum(dist[k-1:]))

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

 

11758번: CCW

첫째 줄에 P1의 (x1, y1), 둘째 줄에 P2의 (x2, y2), 셋째 줄에 P3의 (x3, y3)가 주어진다. (-10,000 ≤ x1, y1, x2, y2, x3, y3 ≤ 10,000) 모든 좌표는 정수이다. P1, P2, P3의 좌표는 서로 다르다.

www.acmicpc.net

 

1. 세 점에 대해 p1, p2 에 대한 첫번째 벡터, p2, p3 에 대한 두 번째 벡터를 구한다.

2. 구한 두 벡터에 대한 외적을 구하고, 구한 값의 부호를 통해 회전하는 방향을 확인한다.

 

dot = list(tuple(map(int,input().split())) for _ in range(3))

def CrossProduct(v1,v2):
    v1_x, v1_y = v1
    v2_x, v2_y = v2
    return (v1_x*v2_y- v2_x*v1_y)

v1 = (dot[1][0]- dot[0][0],dot[1][1] - dot[0][1])
v2 = (dot[2][0]-dot[1][0], dot[2][1] - dot[1][1])
direction = CrossProduct(v1,v2)
if direction > 0:print(1)
elif direction < 0: print(-1)
else: print(0)

 

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

 

2294번: 동전 2

첫째 줄에 n, k가 주어진다. (1 ≤ n ≤ 100, 1 ≤ k ≤ 10,000) 다음 n개의 줄에는 각각의 동전의 가치가 주어진다. 동전의 가치는 100,000보다 작거나 같은 자연수이다. 가치가 같은 동전이 여러 번 주

www.acmicpc.net

 

1. 반복문을 통해 사용 가능한 동전들을 꺼냅니다.

2. 사용 가능한 동전부터 원하는 숫자(k)까지 반복문을 통해, 해당 숫자를 맞추기 위해 동전을 사용하는 가장 적은 횟수를 확인합니다.

 

import sys

input = sys.stdin.readline

n,k = map(int,input().split())

coins = [int(input()) for _ in range(n)]
coins.sort()

dp = [10001] * (k+1)
dp[0] = 0

# 사용 가능한 코인들만 확인
for coin in coins: 
	# coin 부터 구하려는 숫자까지 확인
    for i in range(coin,k+1):
        dp[i] = min(dp[i], dp[i-coin]+1)
if dp[k]== 10001: print(-1)
else: print(dp[k])

+ Recent posts