문제링크

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

 

6593번: 상범 빌딩

당신은 상범 빌딩에 갇히고 말았다. 여기서 탈출하는 가장 빠른 길은 무엇일까? 상범 빌딩은 각 변의 길이가 1인 정육면체(단위 정육면체)로 이루어져있다. 각 정육면체는 금으로 이루어져 있어

www.acmicpc.net

문제설명

 

문제

당신은 상범 빌딩에 갇히고 말았다. 여기서 탈출하는 가장 빠른 길은 무엇일까? 상범 빌딩은 각 변의 길이가 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!

예제 입력 1 복사

3 4 5
S....
.###.
.##..
###.#

#####
#####
##.##
##...

#####
#####
#.###
####E

1 3 3
S##
#E#
###

0 0 0

예제 출력 1 복사

Escaped in 11 minute(s).
Trapped!
문제풀이

3차원을 잘 이해해야 하고,

입력값 받는게 좀 어려웠던것 같다.  (삽질을 좀 많이했다...)

인덱스에 변수로 접근시 맞게 했는지 잘 확인하고 (여기서 실수를 했는데 찾지 못해서 시간이 오래 소요됨..)

 

그거말고는 BFS로 풀면 똑같이 풀린다.

핵심

1. 3차원배열

2. 입력값받기

코드
from collections import deque
    
def BFS(x, y, z):
    queue = deque([(x, y, z)])
    visited[z][x][y] = 0
    while queue:
        curX, curY, curZ = queue.popleft()
        if graph[curZ][curX][curY] == 'E':
            print('Escaped in {0} minute(s).'.format(visited[curZ][curX][curY]))
            return
        for dx, dy, dz in d:
            nx = curX + dx
            ny = curY + dy
            nz = curZ + dz
            if 0 <= nx < R and 0 <= ny < C and 0 <= nz < L and visited[nz][nx][ny] == -1:
                if graph[nz][nx][ny] == '.' or graph[nz][nx][ny] == 'E':
                    queue.append((nx, ny, nz))
                    visited[nz][nx][ny] = visited[curZ][curX][curY] + 1
    
    print('Trapped!')

while True:
    L, R, C = map(int, input().split())
    if L == 0 and R == 0 and C == 0:
        break
    graph = []
    visited = [[[-1 for k in range(C)] for j in range(R)] for i in range(L)]
    d = [(1, 0, 0), (-1, 0, 0), (0, 1, 0), (0, -1, 0), (0, 0, 1), (0, 0, -1)]
    for _ in range(L):
        layer = [list(input()) for _ in range(R)]
        graph.append(layer)
        input()

    for k in range(L):
        for i in range(R):
            for j in range(C):
                if graph[k][i][j] == 'S':
                    BFS(i, j, k)
문제링크

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

 

16234번: 인구 이동

N×N크기의 땅이 있고, 땅은 1×1개의 칸으로 나누어져 있다. 각각의 땅에는 나라가 하나씩 존재하며, r행 c열에 있는 나라에는 A[r][c]명이 살고 있다. 인접한 나라 사이에는 국경선이 존재한다. 모

www.acmicpc.net

문제설명

 

문제

N×N크기의 땅이 있고, 땅은 1×1개의 칸으로 나누어져 있다. 각각의 땅에는 나라가 하나씩 존재하며, r행 c열에 있는 나라에는 A[r][c]명이 살고 있다. 인접한 나라 사이에는 국경선이 존재한다. 모든 나라는 1×1 크기이기 때문에, 모든 국경선은 정사각형 형태이다.

오늘부터 인구 이동이 시작되는 날이다.

인구 이동은 하루 동안 다음과 같이 진행되고, 더 이상 아래 방법에 의해 인구 이동이 없을 때까지 지속된다.

  • 국경선을 공유하는 두 나라의 인구 차이가 L명 이상, R명 이하라면, 두 나라가 공유하는 국경선을 오늘 하루 동안 연다.
  • 위의 조건에 의해 열어야하는 국경선이 모두 열렸다면, 인구 이동을 시작한다.
  • 국경선이 열려있어 인접한 칸만을 이용해 이동할 수 있으면, 그 나라를 오늘 하루 동안은 연합이라고 한다.
  • 연합을 이루고 있는 각 칸의 인구수는 (연합의 인구수) / (연합을 이루고 있는 칸의 개수)가 된다. 편의상 소수점은 버린다.
  • 연합을 해체하고, 모든 국경선을 닫는다.

각 나라의 인구수가 주어졌을 때, 인구 이동이 며칠 동안 발생하는지 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N, L, R이 주어진다. (1 ≤ N ≤ 50, 1 ≤ L ≤ R ≤ 100)

둘째 줄부터 N개의 줄에 각 나라의 인구수가 주어진다. r행 c열에 주어지는 정수는 A[r][c]의 값이다. (0 ≤ A[r][c] ≤ 100)

인구 이동이 발생하는 일수가 2,000번 보다 작거나 같은 입력만 주어진다.

출력

인구 이동이 며칠 동안 발생하는지 첫째 줄에 출력한다.

예제 입력 1 복사

2 20 50
50 30
20 40

예제 출력 1 복사

1
문제풀이

시뮬레이션 문제는 단순히 문제를 이해하기에도 시간이 적지않게 걸리는 것 같다.

더 많은 연습이 필요해보인다...

 

연합이 될 수 있는 조건이 있고,

하루동안 연합국들끼리 인구를 조건에 맞게 이동하는 로직을 구현해야하는 문제다.

 

크게 나눠서,

1. 연합을 정의하는 로직을 BFS함수에 구현하였다.

2. 하루동안 인구를 이동시키는 로직이 그 아래에 있는 메인 코드이다.

 

여기서 개인적으로 생각하는 핵심은,

하루동안 연합이 형성 될때, 이때 연합국이 여러개가 될 수 있다는 점이다.

BFS문제에서 많이 연습했던 구역나누는 로직을 생각해보면 이해가 빠르다.

cf. 적록색약 문제

 

코드
from collections import deque

N, L, R = map(int, input().split())
A = [list(map(int, input().split())) for _ in range(N)]
d = [(-1, 0), (1, 0), (0, -1), (0, 1)]
day = 0

# 여기서 BFS함수는 하루동안 연합인 국가를 정의하는 역할.
def BFS(x, y):
    queue = deque([(x, y)])
    union.append((x, y))
    visited[x][y] = 1

    while queue:
        curX, curY = queue.popleft()

        for dx, dy in d:
            nx = curX + dx
            ny = curY + dy

            if 0 <= nx < N and 0 <= ny < N and not visited[nx][ny]:  
                gap = abs(A[nx][ny] - A[curX][curY])
                # 조건 통과하면 연합 형성. 그러고 방문.
                if L <= gap <= R:
                    visited[nx][ny] = 1
                    queue.append((nx, ny))
                    union.append((nx, ny))
    
    if len(union) > 1:
        return True
    else:
        return False

# 하루 동안 인구 이동 로직.
while True:
    visited = [[0 for _ in range(N)] for _ in range(N)]
    exist = 0

    # 연합국이 여러개 일 수 있으므로 for문 돌려서 BFS시행 (방문한 지역 제외)
    for i in range(N):
        for j in range(N):
            if not visited[i][j]:
                union = []
                # BFS 시행 후 연합국가 있으면
                if BFS(i, j):
                    exist = 1
                    people = sum(A[x][y] for x, y in union)
                    for x, y in union:
                        A[x][y] = people // len(union) 
    
    if not exist:
        print(day)
        break      
    day += 1

 

개인적으로 이해에 도움이 많이 됐던 블로그

https://tmdrl5779.tistory.com/142

문제링크

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

 

17086번: 아기 상어 2

첫째 줄에 공간의 크기 N과 M(2 ≤ N, M ≤ 50)이 주어진다. 둘째 줄부터 N개의 줄에 공간의 상태가 주어지며, 0은 빈 칸, 1은 아기 상어가 있는 칸이다. 빈 칸과 상어의 수가 각각 한 개 이상인 입력만

www.acmicpc.net

문제설명

 

문제

N×M 크기의 공간에 아기 상어 여러 마리가 있다. 공간은 1×1 크기의 정사각형 칸으로 나누어져 있다. 한 칸에는 아기 상어가 최대 1마리 존재한다.

어떤 칸의 안전 거리는 그 칸과 가장 거리가 가까운 아기 상어와의 거리이다. 두 칸의 거리는 하나의 칸에서 다른 칸으로 가기 위해서 지나야 하는 칸의 수이고, 이동은 인접한 8방향(대각선 포함)이 가능하다.

안전 거리가 가장 큰 칸을 구해보자. 

입력

첫째 줄에 공간의 크기 N과 M(2 ≤ N, M ≤ 50)이 주어진다. 둘째 줄부터 N개의 줄에 공간의 상태가 주어지며, 0은 빈 칸, 1은 아기 상어가 있는 칸이다. 빈 칸과 상어의 수가 각각 한 개 이상인 입력만 주어진다.

출력

첫째 줄에 안전 거리의 최댓값을 출력한다.

예제 입력 1 

5 4
0 0 1 0
0 0 0 0
1 0 0 0
0 0 0 0
0 0 0 1

예제 출력 1 

2

 

문제풀이

처음시도한 방법 (이것도 정답코드)

from collections import deque

N, M = map(int, input().split())
graph = [list(map(int, input().split())) for _ in range(N)]
visited = [[0 for _ in range(M)] for _ in range(N)]
dx = [-1, -1, -1, 1, 1, 1, 0, 0]
dy = [0, 1, -1, 0, -1, 1, -1, 1]

def BFS(x, y):
    queue = deque([(x, y, 0)])
    visited[x][y] = 1

    while queue:
        curX, curY, dist = queue.popleft()

        if graph[curX][curY] == 1:
            return dist

        for i in range(8):
            nx = curX + dx[i]
            ny = curY + dy[i]
            if 0 <= nx < N and 0 <= ny < M and not visited[nx][ny]:
                queue.append((nx, ny, dist+1))
                visited[nx][ny] = 1

tmpSet = set()

for i in range(N):
    for j in range(M):
        visited = [[0 for _ in range(M)] for _ in range(N)]
        if graph[i][j] == 0:
            tmpSet.add(BFS(i, j))

print(max(list(tmpSet)))

# 1. 각 좌표마다 1을 만날때까지 BFS 시행하여 최단거리 구해서 임시배열에 저장
# 2. 임시 배열에서 최댓값 구하기

하지만 난 모든 빈 좌표에서 BFS를 시행하여 상어까지의 최단거리를 구했다.

좀 더 최적화가 필요해보여서 생각해낸 방법이,

 

상어가 있는 좌표들에서 시작을 해보자 

=> 연산속도가 훨씬 빨라진다. (4000ms -> 72ms)

 

★핵심

1. 상어가 있는 좌표들을 큐에 전부 삽입.

2. 그러고 나서 큐에 있는거 기반으로 BFS 시행

3. BFS 직후 저장된 안전거리들의 최댓값 산출

코드
from collections import deque

N, M = map(int, input().split())
graph = [list(map(int, input().split())) for _ in range(N)]
d = [(-1, 0), (1, 0), (0, 1), (0, -1), 
     (-1, -1), (-1, 1), (1, -1), (1, 1)]
visited = [[-1 for _ in range(M)] for _ in range(N)]
queue = deque()

def BFS():
    while queue:
        curX, curY = queue.popleft()

        for dx, dy in d:
            nx = curX + dx
            ny = curY + dy
            if 0 <= nx < N and 0 <= ny < M and graph[nx][ny] == 0:
                if visited[nx][ny] == -1:
                    visited[nx][ny] = visited[curX][curY] + 1
                    queue.append((nx, ny))

# 상어좌표 전부 큐에 삽입
for i in range(N):
    for j in range(M):
        if graph[i][j] == 1:
            queue.append((i, j))
            visited[i][j] = 0

# 큐에 좌표 삽입했으니, BFS 시행
BFS()

# BFS 종료후 visited에 삽입된 안전거리의 최댓값 구하기
maxValue = 0
for row in visited:
    maxValue = max(maxValue, max(row))

print(maxValue)

# 상어가 있는 1인 좌표에서 부터 BFS시행 (최단거리를 잼)
문제링크

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

 

8979번: 올림픽

입력의 첫 줄은 국가의 수 N(1 ≤ N ≤ 1,000)과 등수를 알고 싶은 국가 K(1 ≤ K ≤ N)가 빈칸을 사이에 두고 주어진다. 각 국가는 1부터 N 사이의 정수로 표현된다. 이후 N개의 각 줄에는 차례대로 각

www.acmicpc.net

문제설명

 

문제

올림픽은 참가에 의의가 있기에 공식적으로는 국가간 순위를 정하지 않는다. 그러나, 많은 사람들이 자신의 국가가 얼마나 잘 하는지에 관심이 많기 때문에 비공식적으로는 국가간 순위를 정하고 있다. 두 나라가 각각 얻은 금, 은, 동메달 수가 주어지면, 보통 다음 규칙을 따라 어느 나라가 더 잘했는지 결정한다.

  1. 금메달 수가 더 많은 나라 
  2. 금메달 수가 같으면, 은메달 수가 더 많은 나라
  3. 금, 은메달 수가 모두 같으면, 동메달 수가 더 많은 나라 

각 국가는 1부터 N 사이의 정수로 표현된다. 한 국가의 등수는 (자신보다 더 잘한 나라 수) + 1로 정의된다. 만약 두 나라가 금, 은, 동메달 수가 모두 같다면 두 나라의 등수는 같다. 예를 들어, 1번 국가가 금메달 1개, 은메달 1개를 얻었고, 2번 국가와 3번 국가가 모두 은메달 1개를 얻었으며, 4번 국가는 메달을 얻지 못하였다면, 1번 국가가 1등, 2번 국가와 3번 국가가 공동 2등, 4번 국가가 4등이 된다. 이 경우 3등은 없다. 

각 국가의 금, 은, 동메달 정보를 입력받아서, 어느 국가가 몇 등을 했는지 알려주는 프로그램을 작성하시오. 

입력

입력의 첫 줄은 국가의 수 N(1 ≤ N ≤ 1,000)과 등수를 알고 싶은 국가 K(1 ≤ K ≤ N)가 빈칸을 사이에 두고 주어진다. 각 국가는 1부터 N 사이의 정수로 표현된다. 이후 N개의 각 줄에는 차례대로 각 국가를 나타내는 정수와 이 국가가 얻은 금, 은, 동메달의 수가 빈칸을 사이에 두고 주어진다. 전체 메달 수의 총합은 1,000,000 이하이다.

출력

출력은 단 한 줄이며, 입력받은 국가 K의 등수를 하나의 정수로 출력한다. 등수는 반드시 문제에서 정의된 방식을 따라야 한다. 

서브태스크

번호배점제한
1 8 예제 입력, 출력
2 12 N = 2
3 20 모든 국가의 은메달 및 동메달 획득 수는 0
4 25 N ≤ 500
5 35 추가적인 제약 조건은 없다.

예제 입력 1 복사

4 3
1 1 2 0
2 0 1 0
3 0 1 0
4 0 0 1

예제 출력 1 복사

2
문제풀이

구현문제에 취약한 것 같아 연습하고 있는데,

역시나 티어에 비해서 어려운것 같다.. 나만 그런건지 모르겠다.

 

핵심

- ★정렬

  우선순위를 정하여 금메달 인덱스 기준으로 정렬, 은메달, 동메달 순서로 정렬하는 코드

- 여러가지 슬라이싱 문법이나 해당하는 값의 인덱스 뽑기 등 문법 익히기

코드
N, K = map(int, input().split())
medals = [list(map(int, input().split())) for _ in range(N)]
targetIdx = 0

# ★정렬 (금메달우선, 그다음 은메달우선, 그다음 동메달우선) 각각 내림차순으로
sortArr = sorted(medals, key=lambda x: (-x[1], -x[2], -x[3]))

for idx, item in enumerate(sortArr):
    if item[0] == K:
        targetIdx = idx
        
# K국가의 인덱스를 뽑아서 sortArr조회
for i in range(len(sortArr)):
    if sortArr[i][1:] == sortArr[targetIdx][1:]:
        print(i+1)
        break
문제링크

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

 

13913번: 숨바꼭질 4

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일

www.acmicpc.net

문제설명

 

문제

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

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

입력

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

출력

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

둘째 줄에 어떻게 이동해야 하는지 공백으로 구분해 출력한다.

예제 입력 1 복사

5 17

예제 출력 1 복사

4
5 10 9 18 17

예제 입력 2 복사

5 17

예제 출력 2 복사

4
5 4 8 16 17

 

문제풀이

처음 시도한 방법 (틀린 코드)

from collections import deque

N, K = map(int, input().split())
M = 100000
dist = [[-1, []] for _ in range(M+1)]

def BFS(start):
    queue = deque([start])
    dist[start][0] = 0
    dist[start][1].append(start)

    while queue:
        cur = queue.popleft()

        if cur == K:
            print(dist[K][0])
            print(*dist[K][1])

        for next in (cur-1, cur+1, cur*2):
            if 0 <= next <= M:
                if dist[next][0] == -1:                
                    queue.append(next)
                    dist[next][0] = dist[cur][0] + 1
                    for i in dist[cur][1]:
                        dist[next][1].append(i)
                    dist[next][1].append(next)

BFS(N)

 

이렇게 시도했었는데 당연히 각 노드까지의 전체경로를 매번 저장하려고 하니 메모리 초과가 나는건 당연한 일이었다.

 

해결방법

- 각 노드까지 경로 중 직전 노드정보만 저장하자!

 => 그래서 목표노드에 도달하면 역 추적을 통해 경로를 알 수 있다.

코드
from collections import deque

N, K = map(int, input().split())
M = 100000
dist = [[-1, -1] for i in range(M+1)] # 첫번째 인덱스의 값으로 최소시간 저장, 두번째 인덱스 값으로는 직전노드 정보 저장
path = []

def BFS(start):
    queue = deque([start])
    dist[start][0] = 0

    while queue:
        cur = queue.popleft()

        # 목표 노드에 도달하면 dist[cur][1](직전 노드정보)에 있는 원소들을 조회하며 하나씩 역으로 조회하기
        if cur == K:
            print(dist[K][0])
            while cur != -1:
                path.append(cur)
                cur = dist[cur][1]
            for i in range(len(path)-1, -1, -1):
                print(path[i], end=' ')

        for next in (cur-1, cur+1, cur*2):
            if 0 <= next <= M:
                # 방문안한 노드라면 
                if dist[next][0] == -1:                
                    queue.append(next)
                    dist[next][0] = dist[cur][0] + 1
                    dist[next][1] = cur	# 직전 노드 정보 저장

BFS(N)


# 최단시간 출력하고
# 이동 경로까지 출력
문제링크

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

 

12851번: 숨바꼭질 2

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일 때

www.acmicpc.net

문제설명

 

문제

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

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

입력

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

출력

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

둘째 줄에는 가장 빠른 시간으로 수빈이가 동생을 찾는 방법의 수를 출력한다.

예제 입력 1 

5 17

예제 출력 1 

4
2
문제풀이

처음 시도한 코드 (틀린 코드)

from collections import deque

N, K = map(int, input().split())
M = 100000
dist = [(0, 0) for _ in range(M+1)]

def BFS(start):
    queue = deque([start])

    while queue:
        cur = queue.popleft()

        if cur == K:
            print(dist[cur][0])
            print(dist[cur][1])
            return

        for next in (cur-1, cur+1, cur*2):
            if 0 <= next <= M:
                # 이전에 방문한 노드가 아니라면
                if not dist[next][0]:
                    queue.append(next)
                    dist[next] = (dist[cur][0] + 1, 1)
                # 이미 방문한적이 있다면, 더 최소시간으로 갱신
                else:
                    # 방문할 노드의 최소시간과 이미 저장된 최소시간이 같다면 방법수 1증가
                    if dist[next][0] == dist[cur][0] + 1:
                        dist[next] = (dist[next][0], dist[next][1] + dist[cur][1])
                    minValue = min(dist[next][0], dist[cur][0] + 1)
                    dist[next] = (minValue, dist[next][1])

BFS(N)

- 튜플로 처리했었는데 다시보니 코드자체도 굉장히 보기 불편하다...

- 그리고 dist[next] = (dist[cur][0] +1 , 1) 부분이 문제였다

=> 다시 생각하면 당연한 일인데... 1이 아니라 이전값인 dist[cur][1]를 그대로 가져가야한다.

- 최소시간으로 도달하는 방법수를 전부 세야하므로 K에 도달했다고 해서 바로 출력해버리면 안되고 BFS시행이 끝나고 나서 값에 접근해야함

 

핵심

- dist : 열이 2개인 이차원배열로 만든다.

  첫번째 인덱스 원소 : 최소시간을 의미

  두번째 인덱스 원소:  최소시간으로 거리에 도달하는 방법수를 의미

 cf. 처음엔 튜플로 묶었으나 튜플은 불변한 특성이 있기 때문에 값을 변경하기 위해서는 재할당으로 처리해야하는 번거로움이 있다 => 리스트로 묶은 이유.

- 최소시간으로 도달하는 방법수를 다 세야하므로 BFS()시행이 끝난후에 값을 조회하기.

- 숨바꼭질2는 걷기, 순간이동 모두 비용이 1초이므로, 이미 방문한 노드에 대해 최단시간 값 갱신을 할 필요가 없다.

   => BFS로 항상 최단시간 찾기 가능

  cf. 숨바꼭질3은 순간이동 비용이 0초이므로, BFS내에서도 최단시간 값 갱신이 필요하다.

 

코드
from collections import deque

N, K = map(int, input().split())
M = 100000
dist = [[-1, 0] for _ in range(M+1)] #첫번째 인덱스는 최소시간을 의미, 두번째는 최소시간으로 도달하는 방법수를 의미

def BFS(start):
    queue = deque([start])
    dist[start] = [0, 1]

    while queue:
        cur = queue.popleft()

        for next in (cur-1, cur+1, cur*2):
            if 0 <= next <= M:
                # 이전에 방문한 노드가 아니라면
                if dist[next][0] == -1:
                    queue.append(next)
                    dist[next] = [dist[cur][0] + 1, dist[cur][1]]
                # 이미 방문한적이 있다면, 더 최소시간으로 갱신
                else:
                    # 방문할 노드의 최소시간과 이미 저장된 최소시간이 같다면 방법수 1증가
                    if dist[next][0] == dist[cur][0] + 1:
                        dist[next][1] += dist[cur][1]
                    dist[next][0] = min(dist[next][0], dist[cur][0] + 1)
                    

BFS(N)
print(dist[K][0])
print(dist[K][1])
문제링크

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

 

13549번: 숨바꼭질 3

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일 때

www.acmicpc.net

문제설명

 

문제

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

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

입력

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

출력

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

예제 입력 1 

5 17

예제 출력 1 

2
문제풀이

숨바꼭질 문제처럼 BFS 이용하면 된다.

 

핵심

- dist 리스트는 최단시간정보를 저장. (각 인덱스는 거리를 의미한다)

- 순간이동의 비용이 0 이다.

- 즉, 방문한 노드일 경우 최단시간정보를 비교하여 최솟값 갱신할 필요가 있다.

  (이전 숨바꼭질1 , 숨바꼭질2와 다른점)

 

코드
from collections import deque
N, K = map(int, input().split())
M = 100000
dist = [-1] * (M+1) # 해당 인덱스는 거리를 의미, 원소값으로 최단시간정보 저장.

def BFS(start):
    queue = deque([start])
    dist[start] = 0

    while queue:
        cur = queue.popleft()

        for next in (cur-1, cur+1, cur*2):
            if 0 <= next <= M:
                # 방문체크, 방문 안한노드라면
                if dist[next] == -1:
                    queue.append(next)
                    # 순간이동한 경우
                    if next == cur*2:
                        dist[next] = dist[cur]
                    else:
                        dist[next] = dist[cur] + 1
                # 방문한 노드라면
                else:
                    if next == cur*2:
                        dist[next] = min(dist[cur], dist[next])
                    else:
                        dist[next] = min(dist[cur]+1, dist[next])

BFS(N)
print(dist[K])
# 동생을 찾을 수 있는 가장 빠른 시간 찾는 문제

 

문제링크

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

 

2468번: 안전 영역

재난방재청에서는 많은 비가 내리는 장마철에 대비해서 다음과 같은 일을 계획하고 있다. 먼저 어떤 지역의 높이 정보를 파악한다. 그 다음에 그 지역에 많은 비가 내렸을 때 물에 잠기지 않는

www.acmicpc.net

문제설명

 

문제

재난방재청에서는 많은 비가 내리는 장마철에 대비해서 다음과 같은 일을 계획하고 있다. 먼저 어떤 지역의 높이 정보를 파악한다. 그 다음에 그 지역에 많은 비가 내렸을 때 물에 잠기지 않는 안전한 영역이 최대로 몇 개가 만들어 지는 지를 조사하려고 한다. 이때, 문제를 간단하게 하기 위하여, 장마철에 내리는 비의 양에 따라 일정한 높이 이하의 모든 지점은 물에 잠긴다고 가정한다.

어떤 지역의 높이 정보는 행과 열의 크기가 각각 N인 2차원 배열 형태로 주어지며 배열의 각 원소는 해당 지점의 높이를 표시하는 자연수이다. 예를 들어, 다음은 N=5인 지역의 높이 정보이다.

6 8 2 6 2
3 2 3 4 6
6 7 3 3 2
7 2 5 3 6
8 9 5 2 7

이제 위와 같은 지역에 많은 비가 내려서 높이가 4 이하인 모든 지점이 물에 잠겼다고 하자. 이 경우에 물에 잠기는 지점을 회색으로 표시하면 다음과 같다.

6 8 2 6 2
3 2 3 4 6
6 7 3 3 2
7 2 5 3 6
8 9 5 2 7

물에 잠기지 않는 안전한 영역이라 함은 물에 잠기지 않는 지점들이 위, 아래, 오른쪽 혹은 왼쪽으로 인접해 있으며 그 크기가 최대인 영역을 말한다. 위의 경우에서 물에 잠기지 않는 안전한 영역은 5개가 된다(꼭짓점으로만 붙어 있는 두 지점은 인접하지 않는다고 취급한다).

또한 위와 같은 지역에서 높이가 6이하인 지점을 모두 잠기게 만드는 많은 비가 내리면 물에 잠기지 않는 안전한 영역은 아래 그림에서와 같이 네 개가 됨을 확인할 수 있다.

6 8 2 6 2
3 2 3 4 6
6 7 3 3 2
7 2 5 3 6
8 9 5 2 7

이와 같이 장마철에 내리는 비의 양에 따라서 물에 잠기지 않는 안전한 영역의 개수는 다르게 된다. 위의 예와 같은 지역에서 내리는 비의 양에 따른 모든 경우를 다 조사해 보면 물에 잠기지 않는 안전한 영역의 개수 중에서 최대인 경우는 5임을 알 수 있다.

어떤 지역의 높이 정보가 주어졌을 때, 장마철에 물에 잠기지 않는 안전한 영역의 최대 개수를 계산하는 프로그램을 작성하시오.

입력

첫째 줄에는 어떤 지역을 나타내는 2차원 배열의 행과 열의 개수를 나타내는 수 N이 입력된다. N은 2 이상 100 이하의 정수이다. 둘째 줄부터 N개의 각 줄에는 2차원 배열의 첫 번째 행부터 N번째 행까지 순서대로 한 행씩 높이 정보가 입력된다. 각 줄에는 각 행의 첫 번째 열부터 N번째 열까지 N개의 높이 정보를 나타내는 자연수가 빈 칸을 사이에 두고 입력된다. 높이는 1이상 100 이하의 정수이다.

출력

첫째 줄에 장마철에 물에 잠기지 않는 안전한 영역의 최대 개수를 출력한다.

예제 입력 1 

5
6 8 2 6 2
3 2 3 4 6
6 7 3 3 2
7 2 5 3 6
8 9 5 2 7

예제 출력 1 

5
문제풀이

생각보다 문제를 이해하는데 시간이 오래걸렸던 문제다;

주어진 이차원 배열에서 최댓값(높이)을 찾아서,

0부터 최댓값까지 반복문을 돌려 조건에 맞는 좌표에서 BFS를 시행하는 것이 핵심이다.

(아무지역도 잠기지 않을 수 있다 했으므로 범위가 0부터 지정되는것이 맞다.)

 

코드
from collections import deque

N = int(input())
graph = [list(map(int, input().split())) for _ in range(N)]
dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]
maxNum = 0
maxValue = 0

def BFS(x, y, k):
    queue = deque([(x, y)])
    visited[x][y] = 1
    
    while queue:
        curX, curY = queue.popleft()

        for i in range(4):
            nx = curX + dx[i]
            ny = curY + dy[i]
            
            if 0 <= nx < N and 0 <= ny < N and graph[nx][ny] > k and not visited[nx][ny]:
                queue.append((nx, ny))
                visited[nx][ny] = 1

# 입력받은 2차원 배열에서 최댓값 찾는다
for row in graph:
    for item in row:
        maxNum = max(item, maxNum)

# 조건에 맞는 좌표를 시작점으로 BFS 강행
for k in range(maxNum + 1):
    cnt = 0
    visited = [[0 for _ in range(N)] for _ in range(N)]
    
    for i in range(N):
        for j in range(N):
            if graph[i][j] > k and not visited[i][j]:
                BFS(i, j, k)
                cnt += 1
    maxValue = max(cnt, maxValue)
    
print(maxValue)
문제링크

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

 

11723번: 집합

첫째 줄에 수행해야 하는 연산의 수 M (1 ≤ M ≤ 3,000,000)이 주어진다. 둘째 줄부터 M개의 줄에 수행해야 하는 연산이 한 줄에 하나씩 주어진다.

www.acmicpc.net

문제설명

 

문제

비어있는 공집합 S가 주어졌을 때, 아래 연산을 수행하는 프로그램을 작성하시오.

  • add x: S에 x를 추가한다. (1 ≤ x ≤ 20) S에 x가 이미 있는 경우에는 연산을 무시한다.
  • remove x: S에서 x를 제거한다. (1 ≤ x ≤ 20) S에 x가 없는 경우에는 연산을 무시한다.
  • check x: S에 x가 있으면 1을, 없으면 0을 출력한다. (1 ≤ x ≤ 20)
  • toggle x: S에 x가 있으면 x를 제거하고, 없으면 x를 추가한다. (1 ≤ x ≤ 20)
  • all: S를 {1, 2, ..., 20} 으로 바꾼다.
  • empty: S를 공집합으로 바꾼다.

입력

첫째 줄에 수행해야 하는 연산의 수 M (1 ≤ M ≤ 3,000,000)이 주어진다.

둘째 줄부터 M개의 줄에 수행해야 하는 연산이 한 줄에 하나씩 주어진다.

출력

check 연산이 주어질때마다, 결과를 출력한다.

 

문제풀이

어렵지 않게 구현 가능한 문제이다.

 

나는 파이썬의 딕셔너리를 이용하여 풀었지만,

set을 이용하면 더 편할 것 같다.

 

코드
import sys
input = sys.stdin.readline

N = int(input())
dict = {}

def add(x):
    if x not in dict:
        dict[x] = 1

def remove(x):
    if x in dict:
        del dict[x]

def check(x):
    if x in dict:
        print(1)
    else:
        print(0)

def toggle(x):
    if x in dict:
        del dict[x]
    else:
        dict[x] = 1

def all():
    dict.clear()
    for i in range(20):
        dict[i+1] = 1

def empty():
    dict.clear()

for i in range(N):
    num = 0
    arr = input().split()
    
    if len(arr) == 1:
        command = arr[0]
    else:
        command, num = arr[0], arr[1]

    if not num:
        if command == 'all':
            all()
        elif command == 'empty':
            empty()
    else:
        N = int(num)
        if command == 'add':
            add(N)
        elif command == 'check':
            check(N)
        elif command == 'remove':
            remove(N)
        elif command == 'toggle':
            toggle(N)

또 다른 정답코드

import sys
input = sys.stdin.readline

S = set()
N = int(input())

for _ in range(N):
    arr = input().split()

    if len(arr) == 1:
        command = arr[0]
        if command == 'all':
            S = set([i for i in range(1, 21)])
        else:
            S = set()
    else:
        command, num = arr[0], arr[1]
        x = int(num)

        if command == 'add':
            S.add(x)
        elif command == 'remove':
            S.discard(x)
        elif command == 'check':
            print(1 if x in S else 0)
        elif command == 'toggle':
            if x in S:
                S.discard(x)
            else:
                S.add(x)
문제링크

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

 

12865번: 평범한 배낭

첫 줄에 물품의 수 N(1 ≤ N ≤ 100)과 준서가 버틸 수 있는 무게 K(1 ≤ K ≤ 100,000)가 주어진다. 두 번째 줄부터 N개의 줄에 거쳐 각 물건의 무게 W(1 ≤ W ≤ 100,000)와 해당 물건의 가치 V(0 ≤ V ≤ 1,000)

www.acmicpc.net

문제설명

 

문제

이 문제는 아주 평범한 배낭에 관한 문제이다.

한 달 후면 국가의 부름을 받게 되는 준서는 여행을 가려고 한다. 세상과의 단절을 슬퍼하며 최대한 즐기기 위한 여행이기 때문에, 가지고 다닐 배낭 또한 최대한 가치 있게 싸려고 한다.

준서가 여행에 필요하다고 생각하는 N개의 물건이 있다. 각 물건은 무게 W와 가치 V를 가지는데, 해당 물건을 배낭에 넣어서 가면 준서가 V만큼 즐길 수 있다. 아직 행군을 해본 적이 없는 준서는 최대 K만큼의 무게만을 넣을 수 있는 배낭만 들고 다닐 수 있다. 준서가 최대한 즐거운 여행을 하기 위해 배낭에 넣을 수 있는 물건들의 가치의 최댓값을 알려주자.

입력

첫 줄에 물품의 수 N(1 ≤ N ≤ 100)과 준서가 버틸 수 있는 무게 K(1 ≤ K ≤ 100,000)가 주어진다. 두 번째 줄부터 N개의 줄에 거쳐 각 물건의 무게 W(1 ≤ W ≤ 100,000)와 해당 물건의 가치 V(0 ≤ V ≤ 1,000)가 주어진다.

입력으로 주어지는 모든 수는 정수이다.

출력

한 줄에 배낭에 넣을 수 있는 물건들의 가치합의 최댓값을 출력한다.

예제 입력 1 

4 7
6 13
4 8
3 6
5 12

예제 출력 1 

14

 

문제풀이

냅색 알고리즘 핵심

특정 물건을 담지 않았을때 오히려 최선의 선택이 될 수 있음을 고려.

 

D[i][j] : 배낭 무게한도가 j일때, i번째 물건까지 고려했을때 최대가치

 

한도 무게가 더 작으면 현재인덱스에 있는 물건을 고려할 필요 없으므로,

이전 인덱스의 물건까지 고려한 상태에서의 최대가치값으로 저장 => D[i][j] = D[i-1][j]

 

하지마 한도무게가 현재물건 무게보다 크다면,

[1] 이전 물건까지 고려한 dp리스트 값 D[i-1][j-W[i]] 현재물건 가치 V[i] 를 더한 D[i-1][j-W[i] +V[i]

[2] D[i-1][j] 현재 물건안하고 이전에 저장해놓은 최댓값이 더 클수도 있으므로

이 둘의 max값을 구하여 저장

 

코드
N, K = map(int, input().split())
D = [[0 for _ in range(K+1)] for _ in range(N)]
W = [0] * N
V = [0] * N

for i in range(N):
    w, v = map(int, input().split())
    W[i] = w
    V[i] = v

for j in range(W[0], K+1):
    D[0][j] = V[0]

# D[i][j] : 배낭한도무게가 j일때, i번째 물건까지 중 담을 수 있는 최대가치
for i in range(1, N):
    for j in range(1, K+1):
        # 배낭한도무게가 현재차례의 물건의 무게보다 클때
        # 후보 2개중 더 큰값으로 저장
        if j >= W[i]:
            D[i][j] = max(D[i-1][j-W[i]] + V[i], D[i-1][j])
        # 한도무게가 더 작을때
        # 더 넣지 못하므로 이전물건까지 고려한 상태에서의 최대가치로 저장
        else:
            D[i][j] = D[i-1][j]

print(D[N-1][K])

+ Recent posts