728x90

문제

2×n 크기의 직사각형을 1×2, 2×1 타일로 채우는 방법의 수를 구하는 프로그램을 작성하시오.

아래 그림은 2×5 크기의 직사각형을 채운 한 가지 방법의 예이다.

입력

첫째 줄에 n이 주어진다. (1 ≤ n ≤ 1,000)

출력

첫째 줄에 2×n 크기의 직사각형을 채우는 방법의 수를 10,007로 나눈 나머지를 출력한다.

코드

import sys
n = int(sys.stdin.readline())
d = [0]*1001
d[1]=1
d[2]=2
for i in range(3,n+1):
    d[i] = d[i-1]+d[i-2]
print(d[n] % 10007)

풀이

다이나믹 프로그래밍이다.

d[1] = 1

d[2] = 2

d[3] = 3 

d[4] = 5

d[5] = 8

...

규칙이 보인다.

728x90

 

문제

하나 이상의 연속된 소수의 합으로 나타낼 수 있는 자연수들이 있다. 몇 가지 자연수의 예를 들어 보면 다음과 같다.

  • 3 : 3 (한 가지)
  • 41 : 2+3+5+7+11+13 = 11+13+17 = 41 (세 가지)
  • 53 : 5+7+11+13+17 = 53 (두 가지)

하지만 연속된 소수의 합으로 나타낼 수 없는 자연수들도 있는데, 20이 그 예이다. 7+13을 계산하면 20이 되기는 하나 7과 13이 연속이 아니기에 적합한 표현이 아니다. 또한 한 소수는 반드시 한 번만 덧셈에 사용될 수 있기 때문에, 3+5+5+7과 같은 표현도 적합하지 않다.

자연수가 주어졌을 때, 이 자연수를 연속된 소수의 합으로 나타낼 수 있는 경우의 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 자연수 N이 주어진다. (1 ≤ N ≤ 4,000,000)

출력

첫째 줄에 자연수 N을 연속된 소수의 합으로 나타낼 수 있는 경우의 수를 출력한다.

코드

import sys
import math
n = int(sys.stdin.readline())
arr = [False]+[True]*(n)
prime_num = []
for i in range(2,int(math.sqrt(n))+1):
    if arr[i]:
        for j in range(i*2,n+1,i):
            arr[j]=False
for i in range(2,n+1):
    if arr[i]:
        prime_num.append(i)

result = 0
start = 0
end = 0

while end<=len(prime_num):
    tmp = sum(prime_num[start:end])
    if tmp == n:
        result+=1
        end+=1
    elif tmp<n:
        end+=1
    else:
        start+=1
print(result)

풀이

1) 에라토스테네스의 체 알고리즘

한정된 범위 안 소수 구하기

 

2) 투포인터

start, end 변수로 end가 끝이 될때까지, 현재가 원하는 값보다 작으면 end+=1, 아니면 start+=1

728x90

문제

계단 오르기 게임은 계단 아래 시작점부터 계단 꼭대기에 위치한 도착점까지 가는 게임이다. <그림 1>과 같이 각각의 계단에는 일정한 점수가 쓰여 있는데 계단을 밟으면 그 계단에 쓰여 있는 점수를 얻게 된다.

<그림 1>

예를 들어 <그림 2>와 같이 시작점에서부터 첫 번째, 두 번째, 네 번째, 여섯 번째 계단을 밟아 도착점에 도달하면 총 점수는 10 + 20 + 25 + 20 = 75점이 된다.

<그림 2>

계단 오르는 데는 다음과 같은 규칙이 있다.

  1. 계단은 한 번에 한 계단씩 또는 두 계단씩 오를 수 있다. 즉, 한 계단을 밟으면서 이어서 다음 계단이나, 다음 다음 계단으로 오를 수 있다.
  2. 연속된 세 개의 계단을 모두 밟아서는 안 된다. 단, 시작점은 계단에 포함되지 않는다.
  3. 마지막 도착 계단은 반드시 밟아야 한다.

따라서 첫 번째 계단을 밟고 이어 두 번째 계단이나, 세 번째 계단으로 오를 수 있다. 하지만, 첫 번째 계단을 밟고 이어 네 번째 계단으로 올라가거나, 첫 번째, 두 번째, 세 번째 계단을 연속해서 모두 밟을 수는 없다.

각 계단에 쓰여 있는 점수가 주어질 때 이 게임에서 얻을 수 있는 총 점수의 최댓값을 구하는 프로그램을 작성하시오.

입력

입력의 첫째 줄에 계단의 개수가 주어진다.

둘째 줄부터 한 줄에 하나씩 제일 아래에 놓인 계단부터 순서대로 각 계단에 쓰여 있는 점수가 주어진다. 계단의 개수는 300이하의 자연수이고, 계단에 쓰여 있는 점수는 10,000이하의 자연수이다.

출력

첫째 줄에 계단 오르기 게임에서 얻을 수 있는 총 점수의 최댓값을 출력한다.

코드

import sys
n = int(sys.stdin.readline())
d = [0] * 301
s = [0] * 301
for i in range(n):
    s[i] = int(sys.stdin.readline())
    d[0] = s[0]
    d[1] = s[0] + s[1]
    d[2] = max(s[1]+s[2], s[0]+s[2])
    for i in range(3,n):
        d[i] = max(d[i-3]+s[i-1]+s[i], d[i-2]+s[i])
print(d[n-1])

풀이

다이나믹 프로그래밍 문제이다.

n이 6일 때를 그림을 그리면서 점화식을 찾아보자.

 

dp 테이블 d를 만들고 계단의 0번째 값을 넣는다.

1로 가는 길은 0번째 1번째 계단 값을 넣는다.

d[0] = s[0]
d[1] = s[0] + s[1]

2로 가는 길은 0에서 2 or 1에서 2 이다. 

그 중 더 큰 값을 선택한다.

d[2] = max(s[1]+s[2], s[0]+s[2])

그 다음엔 for문을 돌아야하고 마지막 계단은 꼭 밟아야한다.

생각할 것은 마지막 계단 바로 전 계단을 밟을지 or 전전 계단을 밟을지이기 때문에 점화식이 이렇게 된다.

d[i] = max(d[i-3]+s[i-1]+s[i], d[i-2]+s[i])
728x90

문제

정수 X에 사용할 수 있는 연산은 다음과 같이 세 가지 이다.

  1. X가 3으로 나누어 떨어지면, 3으로 나눈다.
  2. X가 2로 나누어 떨어지면, 2로 나눈다.
  3. 1을 뺀다.

정수 N이 주어졌을 때, 위와 같은 연산 세 개를 적절히 사용해서 1을 만들려고 한다. 연산을 사용하는 횟수의 최솟값을 출력하시오.

입력

첫째 줄에 1보다 크거나 같고, 106보다 작거나 같은 정수 N이 주어진다.

출력

첫째 줄에 연산을 하는 횟수의 최솟값을 출력한다.

코드

import sys
n = int(sys.stdin.readline())
#dp 테이블
d = [0]* (10**6+1)

for i in range(2,n+1):
    #1을 뺸다
    d[i] = d[i-1] + 1
    #3으로 나눠 떨어지면
    if i % 3 == 0:
        d[i] = min(d[i], d[i//3]+1)
    #2으로 나눠 떨어지면
    if i % 2 == 0:
        d[i] = min(d[i], d[i//2]+1)

print(d[n])

풀이

다이나믹 프로그래밍으로 풀었다.

n=10일 때, 직접 그림을 그리면서 풀면 규칙을 찾을 수 있다.

 

모든 수가 -1은 가능하다.

2와 3으로 나누어 떨어지는 수만 나누어 주면 되는 것이다.

이때, 1을 더하는 것은 횟수를 세어야 하기 때문이다.

반복문을 돌며, 가장 작은 값을 dp 테이블에 넣는다.

 

i번 째 횟수 = min(i-1, i/3, i/2) +1

728x90

문제

다음 소스는 N번째 피보나치 수를 구하는 C++ 함수이다.

int fibonacci(int n) {
    if (n == 0) {
        printf("0");
        return 0;
    } else if (n == 1) {
        printf("1");
        return 1;
    } else {
        return fibonacci(n‐1) + fibonacci(n‐2);
    }
}

fibonacci(3)을 호출하면 다음과 같은 일이 일어난다.

  • fibonacci(3)은 fibonacci(2)와 fibonacci(1) (첫 번째 호출)을 호출한다.
  • fibonacci(2)는 fibonacci(1) (두 번째 호출)과 fibonacci(0)을 호출한다.
  • 두 번째 호출한 fibonacci(1)은 1을 출력하고 1을 리턴한다.
  • fibonacci(0)은 0을 출력하고, 0을 리턴한다.
  • fibonacci(2)는 fibonacci(1)과 fibonacci(0)의 결과를 얻고, 1을 리턴한다.
  • 첫 번째 호출한 fibonacci(1)은 1을 출력하고, 1을 리턴한다.
  • fibonacci(3)은 fibonacci(2)와 fibonacci(1)의 결과를 얻고, 2를 리턴한다.

1은 2번 출력되고, 0은 1번 출력된다. N이 주어졌을 때, fibonacci(N)을 호출했을 때, 0과 1이 각각 몇 번 출력되는지 구하는 프로그램을 작성하시오.

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다.

각 테스트 케이스는 한 줄로 이루어져 있고, N이 주어진다. N은 40보다 작거나 같은 자연수 또는 0이다.

출력

각 테스트 케이스마다 0이 출력되는 횟수와 1이 출력되는 횟수를 공백으로 구분해서 출력한다.

코드

import sys
t = int(sys.stdin.readline())
for _ in range(t):
    n = int(sys.stdin.readline())
    cnt0 = [1,0]
    cnt1 = [0,1]
    
    if n == 0:
        print(cnt0[0],cnt1[0])
    elif n ==1:
        print(cnt0[1], cnt1[1])
    else:
        for i in range(2,n+1):
            cnt0.append(cnt1[i-1])
            cnt1.append(cnt0[i-1] + cnt1[i-1])
        print(cnt0.pop(), cnt1.pop())

풀이

재귀 함수를 사용하면 시간 초과가 당연히 나고 다이나믹 프로그래밍을 활용해야한다.

Bottom-Up 방법으로 n이 0부터 n까지의 경우의 0과 1이 출현하는 빈도수를 구하자.

n 0출현 1출현
0 1 0
1 0 1
2 1 1
3 1 2
4 2 3
5 3 5

점화식을 만들기 위해 규칙을 찾아보면 다음과 같다.

  • i번째 0 출현 = i-1 번째 1 출현
  • i번째 1 출현 = i-1 번째 0 출현 + i-1 번째 1 출현

n이 0과 1일 때는 리스트에 넣어두고 n이 2일 때부터 반복문을 돌며 점화식을 수행한다.

cnt0과 cnt1 배열의 마지막 원소가 정답이다.

728x90

문제

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일 때 걷는다면 1초 후에 X-1 또는 X+1로 이동하게 된다. 순간이동을 하는 경우에는 1초 후에 2*X의 위치로 이동하게 된다.

수빈이와 동생의 위치가 주어졌을 때, 수빈이가 동생을 찾을 수 있는 가장 빠른 시간이 몇 초 후인지 구하는 프로그램을 작성하시오.

입력

첫 번째 줄에 수빈이가 있는 위치 N과 동생이 있는 위치 K가 주어진다. N과 K는 정수이다.

출력

수빈이가 동생을 찾는 가장 빠른 시간을 출력한다.

코드

import sys
from collections import deque
n, k = map(int,sys.stdin.readline().split())
MAX = 100000
visited = [0] * (MAX+1)

def bfs():
    q = deque()
    q.append(n)
    while q:
        x = q.popleft()
        if x == k:
            print(visited[x])
            break
        for nx in (x-1, x+1, x*2):
            if 0<=nx<=MAX and not visited[nx]:
                visited[nx] = visited[x] + 1
                q.append(nx)
bfs()

풀이

수빈과 동생이 움직일 수 있는 조건이 0부터 100000 니까 max값을 준다.

그리고 bfs을 실행해서 처음 수빈이의 위치를 큐에 넣는다.

수빈이가 동생을 찾을 때까지

수빈이가 움직일 수 있는 경우인 걷기 x-1 와 x+1 , 순간이동 x*2 이 세 가지씩 그래프를 뻗어나간다.

그래프가 한 층씩 생길때마다 전 층의 값 +1을 해주고 동생을 찾으면 이 값을 리턴한다.

728x90

문제

N-Queen 문제는 크기가 N × N인 체스판 위에 퀸 N개를 서로 공격할 수 없게 놓는 문제이다.

N이 주어졌을 때, 퀸을 놓는 방법의 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N이 주어진다. (1 ≤ N < 15)

출력

첫째 줄에 퀸 N개를 서로 공격할 수 없게 놓는 경우의 수를 출력한다.

코드

import sys
n = int(sys.stdin.readline())
chess = [0] * n
cnt = 0

def possible(x):
    for i in range(x):
        #행 돌면서
        #상하좌우 or 대각선에 퀸이 있다면 False 반환
        #여기서 대각선은 행-행 = 열-열
        if chess[i] == chess[x] or abs(chess[x]-chess[i]) == abs(x-i):
            return False
    return True

def solution(x):
    global cnt
    #재귀로 x가 계속 +1 되는데 x가 n이 되면 경우의 수 +1
    if x==n:
        cnt+=1
    else:
        for i in range(n):
            #chess판의 (x,i)에 퀸을 놓는다.
            chess[x] = i
            if possible(x):
                #퀸이 상하좌우, 대각선으로 공격할 수 없다면 다음 퀸 놓기
                solution(x+1)

solution(0)
print(cnt)

풀이

재귀함수 dfs와 백트래킹을 활용해 풀었다.

 

1) 퀸을 체스판에 놓는다.

chess[i] = j 는 ( i, j ) 에 퀸이 있다는 뜻이다.

2) 놓은 퀸의 상하좌우에 퀸이 있으면 False

3) 놓은 퀸의 대각선에 퀸이 있으면 False

4) 퀸의 개수가 입력값일 때 cnt+=1

 

python으로는 계속 시간초과가 난다.

pypy3로 통과했다.

 

python으로 시간초과가 나지 않는 방법이 있으면 알려주세요...

+ Recent posts