문제 설명

1. 1부터 1,000,000,000 까지의 범위를 갖는 n이 주어집니다.

2. 피보나치 수열을 최소의 개수로 더해서 n을 만들었을 때 결과를 리턴해야 합니다.

 

알고리즘

1. 주어진 범위 내에서 가능한 피보나치 수열을 리스트에 담습니다. (1 ≤ n ≤ 1,000,000,000)

2. 이분 탐색 알고리즘을 통해 n보다 작거나 같은 수를 찾습니다. 

3. n에서 찾은 수를 빼줍니다. 

4. n이 0이 될 때 까지 2~3번 과정을 반복합니다.

 

 

코드

import sys
# sys.stdin = open("C:/Users/JIn/PycharmProjects/coding_Test/input.txt", "rt")

fibo = [0, 1]
idx = 0
while fibo[idx + 1] < 1000000000:
    fibo.append(fibo[idx] + fibo[idx + 1])
    idx += 1

t = int(input())
for _ in range(t):
    n = int(input())
    stack = []
    lt = 0
    rt = len(fibo) - 2
    while n != 0:
        while lt <= rt:
            mid = (lt + rt) // 2
            if fibo[mid] > n:
                rt = mid - 1
            else:
                lt = mid + 1
        n -= fibo[rt]
        stack.append(fibo[rt])
        lt = 0
    stack.reverse()
    print(*stack)

 

 

11967번: 불켜기

(1, 1)방에 있는 스위치로 (1, 2)방과 (1, 3)방의 불을 켤 수 있다. 그리고 (1, 3)으로 걸어가서 (2, 1)방의 불을 켤 수 있다. (2, 1)방에서는 다시 (2, 2)방의 불을 켤 수 있다. (2, 3)방은 어두워서 갈 수 없으

www.acmicpc.net


문제 설명

N*N개의 방이 있습니다.

각 방은 (1, 1)부터 (N, N)까지 번호가 매겨져 있습니다.(2≤N≤100).

베시는 최대한 많은 방에 불을 밝히고 싶어 합니다.

 

- 베시는 유일하게 불이 켜져 있는 방인 (1,1) 방에서 출발합니다.

- 각 방에는 다른 방의 불을 끄고 켤 수 있는 스위치가 달려있습니다.

  예를 들어, (1, 1)방에 있는 스위치로 (1, 2) 방의 불을 끄고 켤 수 있습니다.

- 베시는 불이 켜져 있는 방으로만 들어갈 수 있고, 각 방에서는 상하좌우에 인접한 방으로 움직일 수 있습니다. 

 

입력

첫 번째 줄에는 N(2≤N≤100)과, M(1≤M≤20,000)이 정수로 주어집니다.

다음 M 줄에는 네 개의 정수 x, y, a, b가 주어집니다. (x, y) 방에서 (a, b) 방의 불을 켜고 끌 수 있다는 의미입니다.

한 방에 여러 개의 스위치가 있을 수 있고, 하나의 불을 조절하는 스위치 역시 여러개 있을 수 있습니다. 

아래 링크에서 15개의 샘플 케이스를 다운로드 받을 수 있습니다.

www.usaco.org/current/data/lightson_silver_dec15.zip

 

알고리즘

1. 각 방에는 여러 개의 스위치가 있습니다. 따라서 매트릭스를 만들어서 다른 방의 스위치 좌표들을 저장합니다

위 입력을 토대로 한 예시 매트릭스입니다. 이 매트릭스는 switchs라고 부르겠습니다.

2. 스위치의 상태(on/off)와 베스가 이동 가능한 방인지를 표현할 매트릭스를 만듭니다.

이 매트릭스는 board라고 부르겠습니다.

 

불이 꺼진 상태 : 0

불이 켜진 상태 : 1

베스가 이동 가능한 방 : 2

 

베스는 항상 (1, 1)에서 출발한다고 했으므로, (1, 1)의 초기값은 2입니다.

 

 

 

 

 

3. 베스의 출발 지점인 (1, 1)을 queue 리스트에 담습니다.

  - queue 리스트에 들어 있는 좌표는 다른 방의 스위치를 탐색하기 위해 사용됩니다.

  - queue에 리스트에 값이 없어질 때 까지 4 ~ 4-2-1 과정에 대한 반복문이 수행됩니다.

 

4. queue에 있는 좌표 (1, 1)을 빼내고, 해당 좌표의 switchs 매트릭스에 있는 모든 다른 방의 스위치를 누릅니다.

  - 스위치를 켠 방의 상하좌우를 탐색하여 주변에 2가 있는지 확인합니다.

 

4-1. 주변에 2가 없다면 board 매트릭스의 해당 좌표에 1을 입력합니다.

  (불만 켭니다 : 해당 방에는 베스가 들어갈 수 없습니다.)

 

4-2. 주변에 2가 있다면 board 매트릭스의 해당 좌표에 2를 입력합니다.

 (불이 켜져 있는 인접한 방이므로, 베스가 들어갈 수 있습니다.)

  - 주변에 1이 남아 있는 경우를 고려하여, 다시 한 번 상하좌우를 탐색해야 합니다

 

4-2-1. 상하좌우로 인접한 방에 1이 있는지 확인한 후, 존재한다면 2로 수정합니다. 

 -  4-2-1번 작업은 BFS 알고리즘이 재귀적으로 수행되어야 합니다.

 -  2로 수정된 방의 좌표에서는 switchs에 기록된 정보들의 탐색이 이뤄지지 않았으므로, queue에 담습니다.

 

* 4-2-1 작업이 재귀적으로 수행되어야 하는 이유

첫 번째 그림은, 기존에 불 켜져있는 방들이 밀집됐지만, 베스가 들어갈 수 없는 방을 표현했습니다.

두 번째 그림에서 (1, 2)에 불이 켜짐으로써 나머지 (2, 2), (3, 2), (3, 3)도 들어갈 수 있는 방으로 변해야 하는 상황이 되었습니다. 따라서 4-2-1 작업은 재귀적으로 수행되어야 합니다. 그 결과는 세 번째 그림과 같습니다.

 

코드

import sys
from collections import deque
# sys.stdin = open("C:/Users/JIn/PycharmProjects/coding_Test/input.txt", "rt")

n, m = map(int, input().split())  # n : n x n의 방을 만듦, m : m개의 데이터를 받음
dx = [1, -1, 0, 0]
dy = [0, 0, 1, -1]

board = [[0] * (n+1) for _ in range(n+1)]  # 1: 불 켜짐, 2: 이동 가능
board[1][1] = 2
switchs = [[[] for _ in range(n+1)] for _ in range(n+1)]
for _ in range(m):
    x, y, a, b = map(int, input().split())
    switchs[x][y].append([a, b])


def BFS(x, y):
    for i in range(4):
        xx = x + dx[i]
        yy = y + dy[i]
        if 0 < xx <= n and 0 < yy <= n:
            if board[xx][yy] == 1:
                board[xx][yy] = 2
                queue.append([xx, yy])
                BFS(xx, yy)


cnt = 1
queue = deque([[1, 1]])
while queue:
    x, y = queue.popleft()
    for a, b in switchs[x][y]:
        for i in range(4):
            aa = a + dx[i]
            bb = b + dy[i]
            if 0 < aa <= n and 0 < bb <= n:
                if board[a][b] == 2:
                    break

                if board[aa][bb] == 2:
                    cnt += 1
                    board[a][b] = 2
                    queue.append([a, b])
                    BFS(a, b)
                    break
        if board[a][b] == 0:
            board[a][b] = 1
            cnt += 1
print(cnt)

programmers.co.kr/learn/courses/30/lessons/43165

 

코딩테스트 연습 - 타겟 넘버

n개의 음이 아닌 정수가 있습니다. 이 수를 적절히 더하거나 빼서 타겟 넘버를 만들려고 합니다. 예를 들어 [1, 1, 1, 1, 1]로 숫자 3을 만들려면 다음 다섯 방법을 쓸 수 있습니다. -1+1+1+1+1 = 3 +1-1+1+1+

programmers.co.kr


문제 설명

1. 배열 변수인 numbers가 주어진다. ex) [1, 3, 4, 5, 2]

2. int형 변수인 target이 주어진다.

3. 각 numbers를 무작위로 더하거나 빼서 target 값과 같은 개수는?

 

문제 풀이

1. 모든 경우의 수를 찾아야 하므로 완전 탐색 문제 입니다.

2. 더하거나 뺐을 때 나오는 값을 재귀적으로 실행시킵니다.

3. 경우의 수가 만들어질 때 마다 target 값과 sum 값이 같은지 비교후 리턴 합니다.

  - 같다면, cnt를 1씩 올려줍니다.

4. cnt를 정답으로 제출합니다.

 

코드

def solution(numbers, target):
    def DFS(L, sum):
        nonlocal cnt
        if L == len(numbers):
            if sum == target:
                cnt += 1
            return
        else:
            plus = sum + numbers[L]
            DFS(L + 1, plus)
            minus = sum - numbers[L]
            DFS(L + 1, minus)
            
    cnt = 0
    DFS(0, 0) 
    return cnt

 

'코딩 테스트' 카테고리의 다른 글

[백준] 9009 피보나치  (0) 2021.02.10
[백준] 11967 불켜기  (0) 2021.02.10
[백준, 7490] 0 만들기  (0) 2021.02.02
[백준 9576] 책 나눠주기  (0) 2021.02.02
[백준 1946] 신입사원  (0) 2021.02.02

www.acmicpc.net/problem/9576

 

9576번: 책 나눠주기

백준이는 방 청소를 하면서 필요 없는 전공 서적을 사람들에게 나눠주려고 한다. 나눠줄 책을 모아보니 총 N권이었다. 책이 너무 많기 때문에 백준이는 책을 구분하기 위해 각각 1부터 N까지의

www.acmicpc.net


문제

1. N권의 책이 있다. 각 책에는 1부터 N까지 순차대로 번호가 매겨져 있다.

2. M명의 학생이 가지고 싶은 책의 번호를 a b 형태로 제출한다.

3. a부터 b까지의 책 중 남는 것이 있다면 한 개씩 받을 수 있다.

 - 남는 책이 없으면 받지 못한다.

4. 책을 받을 수 있는 최대 학생 수는?

 

알고리즘

1. 학생들이 제출한 목록을 "b를 기준으로 오름차순 --> a를 기준으로 내림차순" 한다.

2. 책의 분배 상태를 의미하는 리스트를 한 개 만든다.

 - 인덱스는 책의 번호를 의미한다.

 - 인덱스 값은 책을 분배했음(1), 분배하지 않음(0)을 의미한다.

3. 학생들이 제출한 범위 내에서 반복문을 진행하고, 책의 분배 상태를 확인한다.

 - 분배되지 않은 책을 발견하면, 리스트의 해당 인덱스를 1로 변경한 후 반복문을 종료한다.

 

* b를 기준으로 오름차순 한 이유

[1, 2][2, 4]의 예제가 존재한다고 가정하자.앞선 학생이 갖는 선택지는 1과 2가 있다.뒷 학생이 갖는 선택지는 2, 3, 4가 있다.

 

만약 앞선 학생이 1번 책을 선택한다면, 뒷 학생은 온전히 2, 3, 4의 선택지를 갖게 된다.

하지만 만약 앞선 학생이 2번 책을 선택한다면, 뒷 학생은 3, 4의 선택지를 갖게 된다.

 

또한, [a, b]에서 b는 언제나 a보다 작거나 같다. (a<=b)

따라서 b가 낮은 학생들이 우선순위를 가져야 한다.

 

* a를 기준으로 내림차순 한 이유

b를 기준으로 오름차순한 상태에서 a를 기준으로 내림차순 한 이유는 다음과 같다.

예를 들어, [2, 3] [1, 3]이 존재한다고 하자.

 

앞선 학생의 경우의 선택지는 2와 3이 있다.

반면에 뒷 학생의 선택지는 1, 2, 3이 있다.

 

따라서 선택지가 더 적은 [2, 3]을 제출한 학생이 우선순위를 가져야 한다.

즉, a를 기준으로 내림차순 해야 한다.

 

 

코드

import sys
# sys.stdin = open("C:/Users/JIn/PycharmProjects/coding_Test/input.txt", "rt")


n = int(input())
for _ in range(n):
    numBooks, numStudents = map(int, input().split())
    queue = [list(map(int, input().split())) for _ in range(numStudents)]
    queue.sort(key=lambda x: x[1])

    status = [0] * (numBooks+1)
    for i in range(numStudents):
        for j in range(queue[i][0], queue[i][1]+1):
            if status[j] == 0:
                status[j] = 1
                break
    print(sum(status))

 

'코딩 테스트' 카테고리의 다른 글

[프로그래머스] 타겟 넘버  (0) 2021.02.08
[백준, 7490] 0 만들기  (0) 2021.02.02
[백준 1946] 신입사원  (0) 2021.02.02
[백준] 회의실 배정  (0) 2021.02.01
[7569] 토마토 | 최대한 상세히 설명하겠습니다  (0) 2021.01.27

www.acmicpc.net/problem/1931

 

1931번: 회의실 배정

(1,4), (5,7), (8,11), (12,14) 를 이용할 수 있다.

www.acmicpc.net


문제설명

1. n개의 회의 스케줄이 주어진다.

2. 각 스케줄에는 (시작시간, 종료시간)이 주어진다.

3. 가장 많은 회의를 진행했을 때 개수는?

4. 단, 회의 시간이 종료되자마자 회의가 시작될 수 있으며, 회의시작 시간과 종료시간이 같을 수 있다.

 

문제 특징

- 회의가 빨리 끝나면 더 많은 회의를 할 수 있다.

하지만 단순히 회의 종료시간을 기준으로 오름차순을 하게 되면 반례에 걸리게 된다.

예를 들어, [5, 5], [5, 5], [4, 5]가 스케줄로 주어진다고 하자.

 

그렇다면 우리가 예상하는 답은 [4, 5], [5, 5], [5, 5]이다.

하지만 만약 회의 시작시간이 내림차순으로 되어 있다면 [5, 5], [5, 5], [4, 5]가 출력이 된다.

따라서 "종료시간(오름차순) -> 시작시간(오름차순)"으로 정렬이 이뤄져야 한다.

 

코드

import sys
import heapq
# sys.stdin = open("C:/Users/JIn/PycharmProjects/coding_Test/input.txt", "rt")

n = int(input())
heap = []
for _ in range(n):
    s, e = map(int, input().split())
    heapq.heappush(heap, (e, s))

cnt = 0
before_e = 0
while heap:
    e, s = heapq.heappop(heap)
    if s >= before_e:
        before_e = e
        cnt += 1
print(cnt)

 

 

7569번: 토마토

첫 줄에는 상자의 크기를 나타내는 두 정수 M,N과 쌓아올려지는 상자의 수를 나타내는 H가 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M ≤ 100, 2 ≤ N ≤ 100,

www.acmicpc.net

 


문제

1. x, y, z 방향으로 BFS를 실행하는 문제다.

2. x, y는 격자무늬 상자 안에 있는 토마토의 좌표를 의미하며, z는 겹쳐 올린 상자의 층을 뜻한다.

3. 상자 안에 있는 토마토는 0, 1, -1의 상태를 가진다. 

(0 : 토마토가 익지 않았다,  1 : 토마토가 익었다,  -1 : 토마토가 존재하지 않는다)

4. 토마토는 매일 "상/하/좌/우/위/아래" 방향으로 전염되어 익는다.

5. 토마토가 익는 데 걸리는 최소 일 수을 출력한다. 

 - 처음부터 모든 토마토가 익었으면 0을 출력한다. 

 - 모든 토마토를 익히지 못한다면 -1을 출력한다. 

알고리즘

1. 3차원 배열에서의 BFS만 구현하면 된다. (기본 2차원 배열에서 배열을 하나 더 추가한 것이다.)

1. 익은 토마토의 좌표를 리스트에 담는다.

2. 익은 토마토를 중심으로 상/하/좌/우/위/아래로 좌표를 이동시킨다.

3. 이동한 좌표가 좌표평면에서 벗어나지 않는다면 계속 진행한다.

4. 이동 전 익은 토마토의 좌표의 값에 1을 더하여 이동 후의 좌표 평면에 1을 더해준다. (매일 주변에 있는 토마토가 익으므로, 좌표평면에 존재하는 값은 "지난 일수"를 의미 한다.)

5. 좌표를 이동함으로써 익게 된 토마토의 좌표를 리스트에 담는다.

 

6. x, y, z 방향으로 3중 반복문을 실행하여 토마토가 전부 익었는지 확인한다.

 - 모두 익지 않았다면 -1을 출력하고 프로그램을 종료한다. 

7. 최대 값(mx)을 1로 초기화한다.

 - 문제 조건에서 처음부터 토마토가 모두 익었으면 0을 출력하라고 했다.

8. x, y, z 방향으로 3중 반복문을 실행하여, mx와 비교하며 좌표 평면에서 가장 큰 수(익는데 걸린 일수)를 찾는다.

9. mx - 1을 해서 정답을 출력한다.

  - 시작 시에 좌표평면의 값이 1이므로, 익는데 걸린 시간에 포함시키지 않는다.

 

코드

import sys
from collections import deque
# sys.stdin = open("C:/Users/JIn/PycharmProjects/coding_Test/input.txt", "rt")


def BFS():
    while queue:
        x, y, z = queue.popleft()
        for dx, dy, dz in mv:
            xx = x + dx
            yy = y + dy
            zz = z + dz
            if 0 <= xx < col and 0 <= yy < row and 0 <= zz < height and board[zz][yy][xx] == 0:
                board[zz][yy][xx] = board[z][y][x] + 1
                queue.append([xx, yy, zz])

if __name__ == '__main__':
    col, row, height = map(int, input().split())
    board = [[list(map(int, input().split())) for _ in range(row)] for _ in range(height)]
    mv = ((1, 0, 0), (-1, 0, 0), (0, 1, 0), (0, -1, 0), (0, 0, 1), (0, 0, -1))

    # 익은 것의 좌표를 찾는다.
    queue = deque()
    for y in range(row):
        for x in range(col):
            for z in range(height):
                if board[z][y][x] == 1:
                    queue.append([x, y, z])

    BFS()
    # 모두 다 익었는지 확인한다.
    for y in range(row):
        for x in range(col):
            for z in range(height):
                if board[z][y][x] == 0:
                    print(-1)
                    sys.exit()

    # 걸린 일수를 출력한다.
    mx = 1
    for z in range(height):
        for y in range(row):
            mx = max(mx, max(board[z][y]))
    print(mx-1)
 

2839번: 설탕 배달

상근이는 요즘 설탕공장에서 설탕을 배달하고 있다. 상근이는 지금 사탕가게에 설탕을 정확하게 N킬로그램을 배달해야 한다. 설탕공장에서 만드는 설탕은 봉지에 담겨져 있다. 봉지는 3킬로그

www.acmicpc.net


문제설명

1. 설탕을 담을 수 있는 3kg짜리 봉투와  5kg짜리 봉투가 있다.

2. 설탕의 무게인 N이 주어졌을 때 사용할 최소의 봉투를 출력하자.

3. 정답이 없다면, -1을 출력한다.

문제 특이사항

- 반례로 N이 11인 상황을 예로 들 수 있습니다.

일반적인 풀이로는 5kg짜리 봉투가 가장 많을 때 답이 된다고 생각할 수 있습니다.

이런 경우에는 5kg짜리 봉투를 2개를 사용한 뒤에 나머지를 3kg짜리 봉투에 담아야 합니다.

그렇게 되면 3kg짜리 봉투에 들어갈 수 있는 설탕의 양은 2kg 밖에 되지 않습니다. 

즉, 문제에서 요구하는 답을 낼 수 없습니다.

 

5kg짜리 봉투 1개에만 적당히 소금을 담고,  3kg짜리 봉투를 2개를 사용하여 설탕을 담으면 문제에서 요구하는 정답을 제출할 수 있습니다.

알고리즘

N이 11로 주어진 상황을 가정하고 설명하겠습니다.

1. 5kg짜리 봉투가 허용하는 최대 무게부터 5 단위로 감소시키며, 0까지 반복문을 실행합니다.

 

2. N에서 5가 허용하는 무게(10, 5, 0)를 뺍니다.

뺀 값은 다시 N에 담습니다.

 

3. N을 3으로 나눕니다. 이 때 나머지가 0이면, 반복문을 빠져나옵니다.

 

4. 답으로는 5의 "'배수(2)'가 되는 값 + N/3의 몫"으로 제출합니다. (나머지가 0인 것이 없다면 -1을 답으로 제출합니다)

 

 

 

 

 

코드

import sys
# sys.stdin = open("C:/Users/JIn/PycharmProjects/coding_Test/input.txt", "rt")

inputData = int(input())
T = inputData//5
answer = -1
for i in range(T, -1, -1):
    n = inputData - (5 * i)
    a, b = divmod(n, 3)
    if b == 0:
        answer = i + a
        break
print(answer)

 

 

코딩테스트 연습 - 구명보트

무인도에 갇힌 사람들을 구명보트를 이용하여 구출하려고 합니다. 구명보트는 작아서 한 번에 최대 2명씩 밖에 탈 수 없고, 무게 제한도 있습니다. 예를 들어, 사람들의 몸무게가 [70kg, 50kg, 80kg, 5

programmers.co.kr


문제

1. 구명보트에 탈 사람들의 몸무게가 리스트(people)로 주어진다. 

2. 구명보트는 최대 2명이 탑승할 수 있다. (단, 구명보트의 최대 탑승 무게(limit) 보다 적어야 한다.)

3. 모든 사람들이 구명보트를 통해 탈출해야 한다.

4. 항상 사람의 무게는 구명보트의 최대 무게보다 작다.

 

문제 특징

1. 효율성 테스트가 상당히 엄격했다. 반드시 1개의 반복문을 통해서만 코드를 작성해야 한다.

2. people이 [30, 40, 60, 70]인 반례 상황이 존재한다. 

[30+40, 60, 70]으로 배를 탈 수도 있지만, [30+70, 40+60]으로 배를 탈 수도 있다. 후자가 문제에서 요구하는 정답이다.

 

알고리즘

- people을 정렬시킨다. 

- 리스트(people)의 맨 앞에서 뒤쪽으로 이동하는 변수를 만든다(front)

- 리스트(people)의 맨 뒤에서 앞쪽으로 이동하는 변수를 만든다(back)

- 반복문에서 back은 항상 왼쪽으로 한 칸씩 움직인다.

- people의 front 번째 값과 back번 째 값을 더해서 limit보다 작거나 같다면 front를 한 칸 오른쪽으로 이동시킨다.

- front보다 back이 작아질 때까지 진행한다.

 

1번 테스트 케이스

people = [70, 50, 80]

limit =  100

 

1. people을 정렬시킨다.

[70, 50, 80] -> [50, 70, 80]

 

2. 

- back과 front를 더하면 limit인 100보다 크므로 front는 가만히 있는다.

- back을 왼쪽으로 한 칸 움직이자

 

3.

- back과 front를 더하면 limit인 100보다 크므로 front는 가만히 있는다.

- back을 왼쪽으로 한 칸 움직이자.

 

- back과 front를 더하면 limit인 100보다 크므로 front는 가만히 있는다.

- back을 왼쪽으로 한 칸 움직이자. (back을 왼쪽으로 움직이면 front보다 앞에 위치하므로, 반복문을 종료한다.)

 

2번 테스트 케이스

people = [30, 40, 50, 60]

limit =  100

 

1. people 정렬한다. [30, 40, 50, 60] -> [30, 40, 50, 60]

 

2.

- back과 front를 더하면 limit인 100보다 작으므로 front도 오른쪽으로 한 칸 움직이자.

- back을 왼쪽으로 한 칸 움직이자. 

 

3.

- back과 front를 더하면 limit인 100보다 작으므로 front도 오른쪽으로 한 칸 움직이자.

- back을 왼쪽으로 한 칸 움직이자. (back이 front보다 앞으로 가게 되므로 반복문이 종료된다.)

 

코드

def solution(people, limit):
    answer = 0
    people = sorted(people)
    front = 0
    back = len(people)-1
    while front < back:
        answer += 1
        if people[front] + people[back] <= limit:
            front += 1
        back -= 1
    return answer

+ Recent posts