[파이썬] 백준 1944번 복제 로봇

작성:

백준 #1944 복제 로봇


  • 미로의 열쇠를 모두 찾아야 한다.
  • 로봇이 열쇠를 찾으면 그 위치에서 복제된다.
  • 복제된 로봇도 열쇠를 찾을 수 있다.
  • 열쇠를 모두 찾은 후 같은 위치로 안 돌아와도 된다.


  • 출력: 모든 로봇이 움직인 횟수의 총 합의 최솟값
    • 불가능한 경우 -1 출력


  • 시작점과 각 열쇠를 정점으로 한 밀집 그래프로 생각한다.
  • 그 밀집 그래프의 최소 신장 트리를 구한다.


1. 프림 알고리즘

from collections import deque


def is_found(y, x, graph, start, key):
    visited = [[0 for i in range(N)] for j in range(N)]
    q = deque([(y, x)])
    visited[y][x] = 1
    dy = [0, 1, 0, -1]
    dx = [1, 0, -1, 0]
    
    reps = 1
    while q:
        for _ in range(len(q)):
            vy, vx = q.popleft()
            for i in range(4):
                ny = vy + dy[i]
                nx = vx + dx[i]
                if 0 <= ny < N and 0 <= nx < N and not visited[ny][nx]:
                    if field[ny][nx] >= 2:
                        e = field[ny][nx]
                        if graph.get(start):
                            graph.get(start).append((e, reps))
                        else:
                            graph[start] = [(e, reps)]
                        q.append((ny, nx))
                        key -= 1
                    elif field[ny][nx] == 0:
                        q.append((ny, nx))
                    visited[ny][nx] = 1
        reps += 1
    
    if key: return False
    else: return True

def prim(graph, start, M):
    minWeight = [float('inf') for i in range(M+3)]
    visited = [0 for i in range(M+3)]
    minWeight[0] = minWeight[1] = minWeight[start] = 0
    
    for i in range(2, M+3):
        minidx, minval = 0, float('inf')
        for j in range(2, M+3):
            if not visited[j] and minWeight[j] < minval:
                minval = minWeight[j]
                minidx = j
        visited[minidx] = 1

        for e, val in graph.get(minidx):
            if not visited[e] and minWeight[e] > val:
                minWeight[e] = val
    
    return sum(minWeight)

def solution(N, M, field):
    nodes = []
    idx = 2
    start = 0
    for i in range(N):
        for j in range(N):
            if field[i][j] == 'S' or field[i][j] == 'K':
                if field[i][j] == 'S': start = idx
                field[i][j] = idx
                idx += 1
                nodes.append((i, j))
            else:
                field[i][j] = int(field[i][j])

    graph = dict()
    for i in range(N):
        for j in range(N):
            if field[i][j] >= 2:
                if not is_found(i, j, graph, field[i][j], M):
                    print(-1)
                    return
    
    print(prim(graph, start, M))

if __name__ == '__main__':
    N, M = map(int, input().split())
    field = [list(input()) for i in range(N)]
    solution(N, M, field)
  • 980 ms



2. 크루스칼 알고리즘

from collections import deque


def is_found(y, x, edges, start, key):
    visited = [[0 for i in range(N)] for j in range(N)]
    q = deque([(y, x)])
    visited[y][x] = 1
    dy = [0, 1, 0, -1]
    dx = [1, 0, -1, 0]
    
    reps = 1
    while q:
        for _ in range(len(q)):
            vy, vx = q.popleft()
            for i in range(4):
                ny = vy + dy[i]
                nx = vx + dx[i]
                if 0 <= ny < N and 0 <= nx < N and not visited[ny][nx]:
                    if field[ny][nx] >= 2:
                        edges.append((reps, start, field[ny][nx]))
                        q.append((ny, nx))
                        key -= 1
                    elif field[ny][nx] == 0:
                        q.append((ny, nx))
                    visited[ny][nx] = 1
        reps += 1
    
    if key: return False
    else: return True

def find(x, parents):
    if parents[x] == x:
        return x
    parents[x] = find(parents[x], parents)
    return parents[x]

def union(x, y, parents, ranks):
    xroot = find(x, parents)
    yroot = find(y, parents)
    if ranks[xroot] >= ranks[yroot]:
        parents[yroot] = xroot
    else:
        parents[xroot] = yroot
    if ranks[xroot] == ranks[yroot]:
        ranks[xroot] += 1

def kruskal(edges):
    parents = [i for i in range(M+3)]
    ranks = [0 for i in range(M+3)]
    edges.sort()
    mst_val = 0
    
    for val, s, e in edges:
        if find(s, parents) != find(e, parents):
            union(s, e, parents, ranks)
            mst_val += val
    
    return mst_val

def solution(N, M, field):
    nodes = []
    idx = 2
    start = 0
    for i in range(N):
        for j in range(N):
            if field[i][j] == 'S' or field[i][j] == 'K':
                if field[i][j] == 'S': start = idx
                field[i][j] = idx
                idx += 1
                nodes.append((i, j))
            else:
                field[i][j] = int(field[i][j])

    edges = []
    for i in range(N):
        for j in range(N):
            if field[i][j] >= 2:
                if not is_found(i, j, edges, field[i][j], M):
                    print(-1)
                    return
    
    print(kruskal(edges))

if __name__ == '__main__':
    N, M = map(int, input().split())
    field = [list(input()) for i in range(N)]
    solution(N, M, field)
  • 996 ms

댓글남기기