문제 설명


문제

지구 온난화로 인하여 북극의 빙산이 녹고 있다. 빙산을 그림 1과 같이 2차원 배열에 표시한다고 하자. 빙산의 각 부분별 높이 정보는 배열의 각 칸에 양의 정수로 저장된다. 빙산 이외의 바다에 해당되는 칸에는 0이 저장된다. 그림 1에서 빈칸은 모두 0으로 채워져 있다고 생각한다.


       
 2453  
 3 252 
 7624  
       
그림 1. 행의 개수가 5이고 열의 개수가 7인 2차원 배열에 저장된 빙산의 높이 정보

빙산의 높이는 바닷물에 많이 접해있는 부분에서 더 빨리 줄어들기 때문에, 배열에서 빙산의 각 부분에 해당되는 칸에 있는 높이는 일년마다 그 칸에 동서남북 네 방향으로 붙어있는 0이 저장된 칸의 개수만큼 줄어든다. 단, 각 칸에 저장된 높이는 0보다 더 줄어들지 않는다. 바닷물은 호수처럼 빙산에 둘러싸여 있을 수도 있다. 따라서 그림 1의 빙산은 일년후에 그림 2와 같이 변형된다.


그림 3은 그림 1의 빙산이 2년 후에 변한 모습을 보여준다. 2차원 배열에서 동서남북 방향으로 붙어있는 칸들은 서로 연결되어 있다고 말한다. 따라서 그림 2의 빙산은 한 덩어리이지만, 그림 3의 빙산은 세 덩어리로 분리되어 있다.


       
  241  
 1 15  
 5412  
       
그림 2

       
   3   
    4  
 32    
       
그림 3

한 덩어리의 빙산이 주어질 때, 이 빙산이 두 덩어리 이상으로 분리되는 최초의 시간(년)을 구하는 프로그램을 작성하시오. 그림 1의 빙산에 대해서는 2가 답이다. 만일 전부 다 녹을 때까지 두 덩어리 이상으로 분리되지 않으면 프로그램은 0을 출력한다.

입력

첫 줄에는 이차원 배열의 행의 개수와 열의 개수를 나타내는 두 정수 N과 M이 한 개의 빈칸을 사이에 두고 주어진다. N과 M은 3 이상 300 이하이다. 그 다음 N개의 줄에는 각 줄마다 배열의 각 행을 나타내는 M개의 정수가 한 개의 빈 칸을 사이에 두고 주어진다. 각 칸에 들어가는 값은 0 이상 10 이하이다. 배열에서 빙산이 차지하는 칸의 개수, 즉, 1 이상의 정수가 들어가는 칸의 개수는 10,000 개 이하이다. 배열의 첫 번째 행과 열, 마지막 행과 열에는 항상 0으로 채워진다.

출력

첫 줄에 빙산이 분리되는 최초의 시간(년)을 출력한다. 만일 빙산이 다 녹을 때까지 분리되지 않으면 0을 출력한다.


풀이 과정


  1. 빙산을 녹이는 과정 시뮬레이션
    • 기존 이차원 배열을 하나 복제해준다.
    • 이차원 배열의 각각의 요소들을 검사하면서, 요소가 0이 아니라면 상하좌우에 0의 개수만큼 빼준다. (음수가 되는 경우 0으로 맞춰줌)
    • 이 과정에서 0이 되는 것이 다른 요소에 영향을 주면 안되므로 복제된 배열에 값을 저장하고, 비교할때는 기존 배열을 사용한다.
  2. BFS를 통해 빙산이 몇덩어리인지 확인한다.
    • 각각의 요소들을 검사하면서, 요소가 0이 아니라면 해당 [행][열]에서 시작해서 BFS를 진행하면서 모두 0으로 맞춰줌.
    • 이 때, 덩어리의 수를 한개 증가시킨다.
  3. 덩어리의 수에 따라 출력해주면 된다. (0개일때, 2개 이상일때)

소스 코드


import sys
import copy
from collections import deque

input = sys.stdin.readline
N, M = map(int, input().rstrip().split())
matrix = [list(map(int, input().rstrip().split())) for _ in range(N)]


def minus(temp, matrix, x, y):
    dx = [-1, 1, 0, 0]
    dy = [0, 0, 1, -1]
    for i in range(4):
        nx = x + dx[i]
        ny = y + dy[i]
        if 0 <= nx and nx < len(matrix) and 0 <= ny and ny < len(matrix[0]):
            if matrix[nx][ny] == 0:
                temp[x][y] -= 1

    if temp[x][y] < 0:
        temp[x][y] = 0

def bfs(matrix, x, y):
    queue = deque([[x, y]])
    matrix[x][y] = 0

    dx = [-1, 1, 0, 0]
    dy = [0, 0, 1, -1]
    while queue:
        x, y = queue.popleft()
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if 0 <= nx and nx < len(matrix) and 0 <= ny and ny < len(matrix[0]):
                if matrix[nx][ny] != 0:
                    matrix[nx][ny] = 0
                    queue.append([nx, ny])
year = 1
while True:
    # 빙산 녹는 과정 시뮬레이션
    temp = copy.deepcopy(matrix)
    for i in range(N):
        for j in range(M):
            if matrix[i][j] != 0:
                minus(temp, matrix, i, j)

    # matrix에 녹은 빙산 저장 
    matrix = copy.deepcopy(temp)

    # 녹은 빙산이 몇덩이인지 bfs로 검사
    total = 0
    for i in range(N):
        for j in range(M):
            if temp[i][j] != 0:
                total += 1
                bfs(temp, i, j)

    # 덩어리의 수에 따라 출력
    if total >= 2:
        print(year)
        break
    elif total == 0:
        print(0)
        break

    year += 1

문제 설명


Given two sorted arraysnums1andnums2of sizemandnrespectively, returnthe medianof the two sorted arrays.

The overall run time complexity should beO(log (m+n)).


Example 1:

Input: nums1 = [1,3], nums2 = [2]
Output: 2.00000
Explanation: merged array = [1,2,3] and median is 2.


Example 2:

Input: nums1 = [1,2], nums2 = [3,4]
Output: 2.50000
Explanation: merged array = [1,2,3,4] and median is (2 + 3) / 2 = 2.5.


Example 3:

Input: nums1 = [0,0], nums2 = [0,0]
Output: 0.00000


Example 4:

Input: nums1 = [], nums2 = [1]
Output: 1.00000


Example 5:

Input: nums1 = [2], nums2 = []
Output: 2.00000


Constraints:

  • nums1.length == m
  • nums2.length == n
  • 0 <= m <= 1000
  • 0 <= n <= 1000
  • 1 <= m + n <= 2000
  • -106<= nums1[i], nums2[i] <= 106

풀이 과정


  • 두개 합쳐서 정렬해서 풀 수도 있지만 오래 걸림.
  1. 따라서, 우선 두개의 리스트를 queue로 바꾼다.
  2. 전체 개수가 홀수일때, 짝수일때 중간값의 위치가 다르다.
    • 홀수일 때 : (두개의 리스트의 길이의 합 // 2)
    • 짝수일 때 : (두개의 리스트의 길이의 합 // 2) - 1, (두개의 리스트의 길이의 합 // 2)
      • 두개를 뽑고 2로 나누어준 값이 중간값
  3. 따라서 홀수일 때는 (두개의 리스트의 길이의 합 // 2) - 1개만큼 뽑아주고, 짝수일 때는 (두개의 리스트의 길이의 합 // 2) - 2개만큼 뽑아준다.
    • 이 다음에 홀수일때는 한개 뽑고, 짝수일때는 두개 뽑아서 중간값 구해주면 됨.
  4. 뽑아줄 때는 두개의 큐의 가장 왼쪽에서 값을 비교하며 하나씩 뽑아준다.
    • 한쪽이 큰 경우 다른쪽에서 뽑아줌.
    • 이 때, 한쪽 큐가 비는 경우 다른쪽 큐에서만 뽑아주면 된다.

소스 코드


class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        from collections import deque

        q1 = deque(nums1)
        q2 = deque(nums2)

        total_length = len(nums1) + len(nums2)
        even = False

        def next_pop(q1, q2):
            temp = 0
            if q1 and q2:
                if q1[0] > q2[0]:
                    temp = q2.popleft()
                else:
                    temp = q1.popleft()
            elif q1:
                temp = q1.popleft()
            elif q2:
                temp = q2.popleft()
            return temp


        if total_length % 2 == 0:
            even = True
            median_idx = total_length // 2 
        else:
            median_idx = total_length // 2 + 1

        for i in range(median_idx-1):
            next_pop(q1, q2)

        answer = 0
        if even:
            answer = next_pop(q1, q2) + next_pop(q1, q2)
            answer = answer / 2
        else:
            answer = next_pop(q1, q2)

        answer = answer * 1.0

        return answer

문제 설명


You are given twonon-emptylinked lists representing two non-negative integers. The digits are stored inreverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list.

You may assume the two numbers do not contain any leading zero, except the number 0 itself.

Example 1:

Input: l1 = [2,4,3], l2 = [5,6,4]
Output: [7,0,8]
Explanation: 342 + 465 = 807.


Example 2:

Input: l1 = [0], l2 = [0]
Output: [0]


Example 3:

Input: l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
Output: [8,9,9,9,0,0,0,1]


Constraints:

  • The number of nodes in each linked list is in the range[1, 100].
  • 0 <= Node.val <= 9
  • It is guaranteed that the list represents a number that does not have leading zeros.

풀이 과정


  1. 먼저 입력받은 두개의 Linked-List를 따라 이동하면서 더해야 하는 수 a,b를 구한다.
    • idx를 10씩 곱해주면서 val * idx를 더해주면 된다.
  2. a, b를 구해주었다면, 합계를 구한 다음 문자열로 바꾸고 뒤집는다.
  3. 뒤집은 수 숫자 한자리씩 Linked-List를 구성하여 주면 된다.
    • 한자리씩 노드를 만들어서, 맨 마지막 노드에 붙여주면 된다.
    • 헤드 노드를 따로 만들어주어야 함 => 리턴할 때 사용
  4. Linked-List의 헤드 노드를 리턴해주면 된다.

소스 코드


# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
        a = 0
        idx = 1
        temp = l1
        while temp:
            a += temp.val * idx
            idx *= 10
            temp = temp.next

        b = 0
        idx = 1
        temp = l2
        while temp:
            b += temp.val * idx
            idx *= 10
            temp = temp.next

        print(a, b)
        c = str(a + b)[::-1]

        head = None
        last = None
        for i in c:
            node = ListNode(val=int(i))
            if head is None:
                head = node

            if last is not None:
                last.next = node
                last = node
            else:
                last = node

        return head

문제 설명


문제

평소에 사이가 좋지 않던 성원이와 형석이가 드디어 제대로 한 판 붙으려고 한다. 성원이와 형석이 둘과 모두 똑같이 친한 인섭이가 대결 종목을 정해 가져왔다. 바로 '나무 탈출' 이라는 보드게임이다.

'나무 탈출' 은 N개의 정점이 있는 트리 모양으로 생긴 게임판과 몇 개의 게임말로 이루어진다. 트리의 각 정점에는 1번부터 N번까지 번호가 붙어있다. 1번 정점은 '루트 노드' 라고 불리며, 이 루트 노드를 중심으로 정점 간에 부모-자식 관계가 만들어진다. 자식이 없는 노드는 '리프 노드' 라고 불린다.

이 게임은 두 사람이 번갈아 가면서 게임판에 놓여있는 게임말을 움직이는 게임이다. 처음에는 트리의 모든 리프 노드에 게임말이 하나씩 놓여있는 채로 시작한다. 어떤 사람의 차례가 오면, 그 사람은 현재 존재하는 게임말 중 아무거나 하나를 골라 그 말이 놓여있던 노드의 부모 노드로 옮긴다. 이 과정에서 한 노드에 여러 개의 게임말이 놓이게 될 수도 있다. 이렇게 옮긴 후에 만약 그 게임말이 루트 노드에 도착했다면 그 게임말을 즉시 제거한다. 모든 과정을 마치면 다음 사람에게 차례를 넘긴다. 이런 식으로 계속 진행하다가 게임말이 게임판에 존재하지 않아 고를 수 없는 사람이 지게 된다.

성원이를 얕본 형석이는 쿨하게 이 게임의 선을 성원이에게 줘버렸다. 따라서 성원이가 먼저 시작하고 형석이가 나중에 시작한다. 그동안 형석이와 대결을 하면 매번 지기만 했던 성원이는 마음속에 분노가 가득 쌓였다. 이번 대결에서는 반드시 이겨서 형석이의 코를 꺾어주고 싶다. 그래서 게임을 시작하기 전에 게임판의 모양만 보고 이 게임을 이길 수 있을지 미리 알아보고 싶어졌다. 성원이가 이 게임을 이길 수 있을지 없을지를 알려주는 프로그램을 만들어 성원이를 도와주자.

입력

첫째 줄에 트리의 정점 개수 N(2 ≤ N ≤ 500,000)이 주어진다.

둘째 줄부터 N-1줄에 걸쳐 트리의 간선 정보가 주어진다. 줄마다 두개의 자연수 a, b(1 ≤ a, b ≤ N, a ≠ b)가 주어지는데, 이는 a와 b 사이에 간선이 존재한다는 뜻이다.

출력

성원이가 최선을 다했을 때 이 게임을 이길 수 있으면 Yes, 아니면 No를 출력한다.


풀이 과정


  1. 루트 노드들의 깊이 합계를 구함.
    • 마지막에 아무것도 없을때 선택하는 사람이 패배이고, 성원이가 먼저 시작하므로
    • 합계를 2로 나누었을때 나누어 떨어지면 패배,
    • 나누어 떨어지지 않으면 승리
  2. 1번 노드에서부터 bfs 진행
    • queue에는 [다음 노드, 단계] 형식으로 저장
    • 루트 노드인 경우, 해당 노드의 단계를 합계에 더해줌.
  3. 루트 노드의 깊이 합계를 2로 나누었을때 나누어 떨어지면 패배, 나누어 떨어지지 않으면 승리를 출력한다.

소스 코드


import sys
from collections import deque

input = sys.stdin.readline

N = int(input().rstrip())
tree = [[] for _ in range(N+1)]
for _ in range(N-1):
    a, b = map(int, input().rstrip().split())
    tree[a].append(b)
    tree[b].append(a)

leap_depth = []
queue = deque([[1,0]])
visited = [False] * (N+1)
visited[1] = True
total_leaf_depth = 0
while queue:
    node, depth = queue.popleft()
    if len(tree[node]) == 1 and visited[tree[node][0]]:
        total_leaf_depth += depth
        continue

    for t in tree[node]:
        if not visited[t]:
            queue.append([t, depth+1])
            visited[t] = True


if total_leaf_depth % 2 == 1:
    print('Yes')
else:
    print('No')

문제 설명


문제

그래프는 정점과 간선으로 이루어져 있다. 두 정점 사이에 경로가 있다면, 두 정점은 연결되어 있다고 한다. 연결 요소는 모든 정점이 서로 연결되어 있는 정점의 부분집합이다. 그래프는 하나 또는 그 이상의 연결 요소로 이루어져 있다.

트리는 사이클이 없는 연결 요소이다. 트리에는 여러 성질이 있다. 예를 들어, 트리는 정점이 n개, 간선이 n-1개 있다. 또, 임의의 두 정점에 대해서 경로가 유일하다.

그래프가 주어졌을 때, 트리의 개수를 세는 프로그램을 작성하시오.

입력

입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스의 첫째 줄에는 n ≤ 500과 m ≤ n(n-1)/2을 만족하는 정점의 개수 n과 간선의 개수 m이 주어진다. 다음 m개의 줄에는 간선을 나타내는 두 개의 정수가 주어진다. 같은 간선은 여러 번 주어지지 않는다. 정점은 1번부터 n번까지 번호가 매겨져 있다. 입력의 마지막 줄에는 0이 두 개 주어진다.

출력

입력으로 주어진 그래프에 트리가 없다면 "No trees."를, 한 개라면 "There is one tree."를, T개(T > 1)라면 "A forest of T trees."를 테스트 케이스 번호와 함께 출력한다.


풀이 과정


  1. 입력받은 간선들을 순차적으로 방문하면서 각각의 간선들의 두 정점을 Union 해준다.
    • 이 때, 두 정점이 같은 그룹에 있는 경우 싸이클이 형성됨 => 트리가 아니란 걸 알 수 있음.
    • 맨 마지막에 처리하기 위해 두 정점중 하나의 정점을 따로 저장
  2. (1)번에서 따로 저장해둔 정점이 어떤 그룹에 속해있는지 저장
    • 해당 그룹은 사이클이 형성된 그룹이므로 방문하지 않아야 함.
  3. 전체 정점에 대해서, 방문하지 않은 그룹이면서 사이클이 형성되지 않은 그룹이라면
    • 해당 그룹 방문처리 / 정답 개수 하나 증가
  4. 그룹 개수에 따라 다르게 print

소스 코드


import sys
from collections import deque

input = sys.stdin.readline

def find(parent, a):
    if parent[a] != a:
        parent[a] = find(parent, parent[a])

    return parent[a]

def union(parent, a, b):
    p1 = find(parent, a)
    p2 = find(parent, b)
    if p1 != p2:
        if p1 > p2:
            parent[p1] = p2
        else:
            parent[p2] = p1

case = 0
while True:
    n, m = map(int, input().rstrip().split())
    if n == 0 and m == 0:
        break
    parent = [i for i in range(n+1)]
    cycle = []
    for _ in range(m):
        a, b = map(int, input().rstrip().split())
        p1 = find(parent, a)
        p2 = find(parent, b)
        if p1 != p2:
            union(parent, a, b)
        else:
            # cycle이 발생한 케이스이므로 따로 저장
            cycle.append(a)
    # 갱신
    for i in range(n+1):
        find(parent, i)

    # cycle이 있는 그룹들 저장
    group = set()
    for cycle_vertex in cycle:
        group.add(parent[cycle_vertex])

    answer = 0
    for i in range(1, n+1):
        if parent[i] in group:
            continue
        answer += 1
        group.add(parent[i])

    case += 1
    if answer == 0:
        print("Case %d: No trees."%(case))
    elif answer == 1:
        print("Case %d: There is one tree."%(case))
    else:
        print("Case %d: A forest of %d trees."%(case, answer))

문제 설명


문제

총 N개의 시험장이 있고, 각각의 시험장마다 응시자들이 있다. i번 시험장에 있는 응시자의 수는 Ai명이다.

감독관은 총감독관과 부감독관으로 두 종류가 있다. 총감독관은 한 시험장에서 감시할 수 있는 응시자의 수가 B명이고, 부감독관은 한 시험장에서 감시할 수 있는 응시자의 수가 C명이다.

각각의 시험장에 총감독관은 오직 1명만 있어야 하고, 부감독관은 여러 명 있어도 된다.

각 시험장마다 응시생들을 모두 감시해야 한다. 이때, 필요한 감독관 수의 최솟값을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 시험장의 개수 N(1 ≤ N ≤ 1,000,000)이 주어진다.

둘째 줄에는 각 시험장에 있는 응시자의 수 Ai(1 ≤ Ai≤ 1,000,000)가 주어진다.

셋째 줄에는 B와 C가 주어진다. (1 ≤ B, C ≤ 1,000,000)

출력

각 시험장마다 응시생을 모두 감독하기 위해 필요한 감독관의 최소 수를 출력한다.


풀이 과정


  1. 전체 시험장에 먼저 총감독관을 배치한다.
    • 각 시험장의 응시자의 수에서 총감독관이 감시할 수 있는 응시자의 수를 빼준다.
    • 빼주면서, 감독관의 수를 하나 증가시킨다.
  2. 다음으로, 각 시험장에 부감독관을 배치한다.
    • 시험장에 필요한 부감독관의 수는 다음과 같다.
      • round(각 시험장의 잔여 인원 수 / 부감독관이 감시할 수 있는 인원 수)
    • 나머지가 있으면 1 증가하는 방식으로 구현함.
    • 감독관의 수를 필요한 부감독관의 수만큼 늘려준다.
  3. 전체 감독관의 수를 출력해주면 된다.

풀이 과정


import sys

input = sys.stdin.readline
N = int(input().rstrip())
exam = list(map(int, input().rstrip().split()))
B, C = map(int, input().rstrip().split())

answer = 0

for i in range(len(exam)):
    exam[i] -= B
    answer += 1

for i in range(len(exam)):
    if exam[i] <= 0:
        continue
    answer += (exam[i] // C)
    if exam[i] % C != 0:
        answer += 1

print(answer)

문제 설명


문제

N개의 수로 된 수열 A[1], A[2], …, A[N] 이 있다. 이 수열의 i번째 수부터 j번째 수까지의 합 A[i] + A[i+1] + … + A[j-1] + A[j]가 M이 되는 경우의 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N(1 ≤ N ≤ 10,000), M(1 ≤ M ≤ 300,000,000)이 주어진다. 다음 줄에는 A[1], A[2], …, A[N]이 공백으로 분리되어 주어진다. 각각의 A[x]는 30,000을 넘지 않는 자연수이다.

출력

첫째 줄에 경우의 수를 출력한다.


풀이 과정

  1. left를 구간의 왼쪽(포함), right를 구간의 오른쪽(포함 X)으로 둔다.
    • 구간을 왼쪽에서 오른쪽으로 이동시키면서 합계가 M이 되는 구간을 찾는게 목표
  2. 만약 구간의 합계가 M보다 크다면, 구간의 합계를 줄여야 하므로 left를 한칸 오른쪽으로 이동시켜서, 구간을 좁힘.
  3. 만약 구간의 합계가 M보다 작거나 같다면, 구간의 합계를 늘려야 하므로 right를 한칸 오른쪽으로 이동시켜서 구간을 넓힘.
  4. 구간의 합계가 M이라면 갯수를 하나 증가시킨다.
  • while문에서 <=로 해야함에 유의. left == right일때도 봐주어야 함. (합계가 0)

소스 코드

import sys

input = sys.stdin.readline
N, M = map(int, input().rstrip().split())

sequence = list(map(int, input().rstrip().split()))
left = 0
right = 1
sumation = sequence[left]
answer = 0
while left <= right:
    if sumation == M:
        answer += 1

    # 합계가 M보다 크다면 왼쪽에서 하나 끌고와서 빼준다.
    if sumation > M:
        sumation -= sequence[left]
        left += 1
    # 합계가 M보다 작거나 같다면 오른쪽으로 한칸 늘려준다.
    elif sumation <= M:
        if right == N:
            break
        sumation += sequence[right]
        right += 1

print(answer)


문제 설명


문제

당신은 상범 빌딩에 갇히고 말았다. 여기서 탈출하는 가장 빠른 길은 무엇일까? 상범 빌딩은 각 변의 길이가 1인 정육면체(단위 정육면체)로 이루어져있다. 각 정육면체는 금으로 이루어져 있어 지나갈 수 없거나, 비어있어서 지나갈 수 있게 되어있다. 당신은 각 칸에서 인접한 6개의 칸(동,서,남,북,상,하)으로 1분의 시간을 들여 이동할 수 있다. 즉, 대각선으로 이동하는 것은 불가능하다. 그리고 상범 빌딩의 바깥면도 모두 금으로 막혀있어 출구를 통해서만 탈출할 수 있다.

당신은 상범 빌딩을 탈출할 수 있을까? 만약 그렇다면 얼마나 걸릴까?

입력

입력은 여러 개의 테스트 케이스로 이루어지며, 각 테스트 케이스는 세 개의 정수 L, R, C로 시작한다. L(1 ≤ L ≤ 30)은 상범 빌딩의 층 수이다. R(1 ≤ R ≤ 30)과 C(1 ≤ C ≤ 30)는 상범 빌딩의 한 층의 행과 열의 개수를 나타낸다.

그 다음 각 줄이 C개의 문자로 이루어진 R개의 행이 L번 주어진다. 각 문자는 상범 빌딩의 한 칸을 나타낸다. 금으로 막혀있어 지나갈 수 없는 칸은 '#'으로 표현되고, 비어있는 칸은 '.'으로 표현된다. 당신의 시작 지점은 'S'로 표현되고, 탈출할 수 있는 출구는 'E'로 표현된다. 각 층 사이에는 빈 줄이 있으며, 입력의 끝은 L, R, C가 모두 0으로 표현된다. 시작 지점과 출구는 항상 하나만 있다.

출력

각 빌딩에 대해 한 줄씩 답을 출력한다. 만약 당신이 탈출할 수 있다면 다음과 같이 출력한다.

Escaped in x minute(s).

여기서 x는 상범 빌딩을 탈출하는 데에 필요한 최단 시간이다.

만일 탈출이 불가능하다면, 다음과 같이 출력한다.

Trapped!


풀이 과정

  • 3차원 BFS 문제이다.

    • 큐에는 [x, y, z, 비용] 형식으로 저장
    • 시작점에서부터 시작하여 동,서,남,북,상,하를 방문하지 않았으면서 길이 있다면 큐에 다음 지점 저장 / 방문 처리
    • 만약 Queue가 비게 된다면 출구를 찾지 못한 케이스이므로 Trapped 출력
    • 만약 Queue에서 뺀 점이 출구라면 몇번 이동하였는지 출력
  • 3차원 BFS 문제의 경우는 구현을 많이 신경써야 할 것 같음.. 몇번의 컴파일 에러가 있었음.


소스 코드


import sys
import copy
from collections import deque

input = sys.stdin.readline

def input_matrix(matrix, R):
    floor = [list(input().rstrip()) for _ in range(R)]
    matrix.append(floor)

def get_start_point(matrix):
    for i in range(len(matrix)):
        for j in range(len(matrix[0])):
            for k in range(len(matrix[0][0])):
                if matrix[i][j][k] == 'S':
                    return [i, j, k, 0]

while True:
    L, R, C = map(int, input().rstrip().split())
    if L == 0 and R == 0 and C == 0:
        break

    matrix = []
    for _ in range(L):
        input_matrix(matrix, R)
        input() # 1칸 띄워줌

    start = get_start_point(matrix)
    visited = copy.deepcopy(matrix)
    dx = [-1, 1, 0, 0, 0, 0]
    dy = [0, 0, 1, -1, 0, 0]
    dz = [0, 0, 0, 0, 1, -1]

    queue = deque([start])
    answer = -1
    while queue:
        x, y, z, cost = queue.popleft()
        if matrix[x][y][z] == 'E':
            answer = cost
            break
        for i in range(6):
            nx, ny, nz = x + dx[i], y + dy[i], z + dz[i]
            if 0 <= nx and nx < L and 0 <= ny and ny < R and 0 <= nz and nz < C:
                if not visited[nx][ny][nz] == 'O' and matrix[nx][ny][nz] != '#':
                    queue.append([nx, ny, nz, cost+1])
                    visited[nx][ny][nz] = 'O'

    if answer != -1:
        print("Escaped in %d minute(s)."%(answer))
    else:
        print("Trapped!")

문제 설명


문제

강토는 자신의 기타 레슨 동영상을 블루레이로 만들어 판매하려고 한다. 블루레이에는 총 N개의 레슨이 들어가는데, 블루레이를 녹화할 때, 레슨의 순서가 바뀌면 안 된다. 순서가 뒤바뀌는 경우에는 레슨의 흐름이 끊겨, 학생들이 대혼란에 빠질 수 있기 때문이다. 즉, i번 레슨과 j번 레슨을 같은 블루레이에 녹화하려면 i와 j 사이의 모든 레슨도 같은 블루레이에 녹화해야 한다.

강토는 이 블루레이가 얼마나 팔릴지 아직 알 수 없기 때문에, 블루레이의 개수를 가급적 줄이려고 한다. 오랜 고민 끝에 강토는 M개의 블루레이에 모든 기타 레슨 동영상을 녹화하기로 했다. 이때, 블루레이의 크기(녹화 가능한 길이)를 최소로 하려고 한다. 단, M개의 블루레이는 모두 같은 크기이어야 한다.

강토의 각 레슨의 길이가 분 단위(자연수)로 주어진다. 이때, 가능한 블루레이의 크기 중 최소를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 레슨의 수 N (1 ≤ N ≤ 100,000)과 M (1 ≤ M ≤ N)이 주어진다. 다음 줄에는 강토의 기타 레슨의 길이가 레슨 순서대로 분 단위로(자연수)로 주어진다. 각 레슨의 길이는 10,000분을 넘지 않는다.

출력

첫째 줄에 가능한 블루레이 크기중 최소를 출력한다.


풀이 과정

  1. blueray의 길이를 절반씩 조사한다.
    • 초기 범위를 레슨들중 최대 길이 ~ 100000 * 10000으로 설정(최대 레슨의 길이 * 최대 레슨의 수)
    • 중간 길이 middle에 대해서
      1. 전체 레슨들을 듣는데 몇개의 blueray가 필요한지 계산
      2. blueray의 개수가 M보다 작거나 같다면, 길이의 최솟값을 구해야 하므로 정답 저장 후 왼쪽 구간에 대해서 진행
      3. blueray의 개수가 M보다 크다면 길이를 늘려야 하므로, 오른쪽 구간에 대해서 진행

틀렸던 점

  1. blueray의 초기 범위를 0부터 했다가 틀림.
    • 레슨이 10이라고 할때, blueray를 5 5로 할 수 없음.
  2. 처음에는 blueray의 개수가 M과 같을때만 정답에 저장하였으나.. M보다 작거나 같을때로 수정하여야 함.
    • M보다 작다면 맞출 수 있으므로
      • M = 2, [1, 2, 3] 이라고 할 때
      • 예시로 길이가 6일때 [1, 2, 3] 모두 포함되나..
      • 1에다가 blueray 하나를 통째로 주고 [2, 3]에 blueray 하나를 주는 방식으로 두개 맞출수 있음.

소스 코드

import sys

input = sys.stdin.readline
N, M = map(int, input().rstrip().split())
lessons = list(map(int, input().rstrip().split()))

left = max(lessons)
right = 100000 * 10000

answer = max(lessons)

while left <= right:
    # middle : blueray의 길이
    middle = (left + right) // 2

    blueray = 1
    current = middle

    # blueray의 길이가 middle일때 몇개 나오는지 
    for lesson in lessons:
        if current - lesson < 0:
            blueray += 1
            current = middle - lesson
        else:
            current = current - lesson

    # blueray의 길이가 M보다 작다면 정답 저장 후 blueray를 줄여야 함
    # blueray의 길이가 M보다 크다면 blueray를 늘려야 함
    if blueray <= M:
        answer = middle
        right = middle - 1
    elif blueray > M:
        left = middle + 1

print(answer)

문제 설명


문제

요즘 민규네 동네에서는 스타트링크에서 만든 PS카드를 모으는 것이 유행이다.

PS카드는 PS(Problem Solving)분야에서 유명한 사람들의 아이디와 얼굴이 적혀있는 카드이다. 각각의 카드에는 등급을 나타내는 색이 칠해져 있고, 다음과 같이 8가지가 있다.

  • 전설카드
  • 레드카드
  • 오렌지카드
  • 퍼플카드
  • 블루카드
  • 청록카드
  • 그린카드
  • 그레이카드

카드는 카드팩의 형태로만 구매할 수 있고, 카드팩의 종류는 카드 1개가 포함된 카드팩, 카드 2개가 포함된 카드팩, ... 카드 N개가 포함된 카드팩과 같이 총 N가지가 존재한다.

민규는 카드의 개수가 적은 팩이더라도 가격이 비싸면 높은 등급의 카드가 많이 들어있을 것이라는 미신을 믿고 있다. 따라서, 민규는 돈을 최대한 많이 지불해서 카드 N개 구매하려고 한다. 카드가 i개 포함된 카드팩의 가격은 Pi원이다.

예를 들어, 카드팩이 총 4가지 종류가 있고, P1= 1, P2= 5, P3= 6, P4= 7인 경우에 민규가 카드 4개를 갖기 위해 지불해야 하는 금액의 최댓값은 10원이다. 2개 들어있는 카드팩을 2번 사면 된다.

P1= 5, P2= 2, P3= 8, P4= 10인 경우에는 카드가 1개 들어있는 카드팩을 4번 사면 20원이고, 이 경우가 민규가 지불해야 하는 금액의 최댓값이다.

마지막으로, P1= 3, P2= 5, P3= 15, P4= 16인 경우에는 3개 들어있는 카드팩과 1개 들어있는 카드팩을 구매해 18원을 지불하는 것이 최댓값이다.

카드 팩의 가격이 주어졌을 때, N개의 카드를 구매하기 위해 민규가 지불해야 하는 금액의 최댓값을 구하는 프로그램을 작성하시오. N개보다 많은 개수의 카드를 산 다음, 나머지 카드를 버려서 N개를 만드는 것은 불가능하다. 즉, 구매한 카드팩에 포함되어 있는 카드 개수의 합은 N과 같아야 한다.

입력

첫째 줄에 민규가 구매하려고 하는 카드의 개수 N이 주어진다. (1 ≤ N ≤ 1,000)

둘째 줄에는 Pi가 P1부터 PN까지 순서대로 주어진다. (1 ≤ Pi≤ 10,000)

출력

첫째 줄에 민규가 카드 N개를 갖기 위해 지불해야 하는 금액의 최댓값을 출력한다.


풀이 과정

  1. 현재 i장의 카드라고 할때, 현재 카드에 도달하기 위해서는
    • i-1장의 카드에서 1장짜리 카드팩 구매
    • i-2장의 카드에서 2장짜리 카드팩 구매
    • ...
  2. 따라서, i-k장의 카드의 가격 + k장의 카드 가격이 최대가 되는 값을 dp[i]의 값으로 하면 된다.
  3. 위 과정을 1부터 N까지 반복
  4. dp[N] 출력

소스 코드

import sys

input = sys.stdin.readline

N = int(input().rstrip())

cards = list(map(int, input().rstrip().split()))
dp = [0] * (N+1)
for i in range(1, N+1):
    for idx, cost in enumerate(cards):
        ridx = idx + 1 # enumerate가 0부터 시작하므로 1 더해야..
        if i - ridx >= 0:
            dp[i] = max(dp[i], dp[i-ridx] + cost)
        else:
            break

print(dp[N])

+ Recent posts