티스토리 뷰

Algorithm

[SWEA][stack] 4875_미로 (211018)

lluna 2021. 10. 18. 23:01

이해도

★★★☆☆

문제

접근방법

[공통]

  • 함수에서 이차원 배열과 시작점의 x 및 y 좌표를 파라미터로 사용한다.
  • 델타 탐색으로 진행한다.
  • 이차원의 visited 배열(0 또는 False)을 만들어 방문처리한다.
  • 벽을 빠져나가지 않도록 처리한다.(추가 벽을 세우거나, 델타 범위를 제한한다.)

[다양한 방식]

  • 1. DFS 사용
    • 1-1. 스택 사용하여 반복문으로 구현
    • 1-2. 재귀함수로 구현
  • 2. DFS 사용하지 않고 구현(스택.pop()대신 좌표를 감소시킴)

 

나의 코드

스택 사용한 반복 DFS 구현

def dfs(board, start):
    visited = [[False] * N for _ in range(N)]
    stack = [start]

    while stack:
        curr = stack.pop()
        visited[curr[0]][curr[1]] = True

        for i in range(4):
            if curr[0] + dr[i] in range(N) and curr[1] + dc[i] in range(N):
                if board[curr[0] + dr[i]][curr[1] + dc[i]] == 3:
                    return True
                if board[curr[0] + dr[i]][curr[1] + dc[i]] == 0 and not visited[curr[0] + dr[i]][curr[1] + dc[i]]:
                    stack.append((curr[0] + dr[i], curr[1] + dc[i]))
    return False


T = int(input())
for tc in range(1, T+1):
    N = int(input())
    board = [list(map(int, input())) for _ in range(N)]

    for r in range(N):
        for c in range(N):
            if board[r][c] == 2:
                start = (r, c)

    dr = [-1, 1, 0, 0]
    dc = [0, 0, -1, 1]

    ans = dfs(board, start)
    print(f"#{tc} {ans}")

 

방법별 코드

1-1. 스택 사용하여 반복문으로 구현 (벽감싸기)

# 벽감싸기 + stack 반복문 활용

dx = [0, 1, 0, -1]
dy = [1, 0, -1, 0]

T = int(input())
for tc in range(1, T + 1):
    N = int(input())
    lst = [[1] * (N + 2)] + [[1] + list(map(int, list(input()))) + [1] for _ in range(N)] + [[1] * (N + 2)]
    for r in range(N + 2):
        for c in range(N + 2):
            if lst[r][c] == 2:
                start = (r, c)
            elif lst[r][c] == 3:
                end = (r, c)

    stack = [start]
    path = [[0] * (N + 2) for _ in range(N + 2)] # visited 역할
    result = 0
    while stack:
        curr = stack.pop()
        path[curr[0]][curr[1]] = 1
        if curr == end:
            result = 1
        # 주위 탐색
        for i in range(4):
            if lst[curr[0] + dx[i]][curr[1] + dy[i]] == 3:  # 주위에 3, 즉 도착점이 있다면 마찬가지로 끝.
                result = 1
            if lst[curr[0] + dx[i]][curr[1] + dy[i]] == 0 and path[curr[0] + dx[i]][curr[1] + dy[i]] == 0:
                stack.append((curr[0] + dx[i], curr[1] + dy[i]))
        # if result == 1:
        #     break

    print('#{} {}'.format(tc, result))

 

1-1. 스택 사용하여 반복문으로 구현2 (상하바꾸기, 불리언 사용)

# boolean 활용
# 상하를 바꾸고 스택을 사용하여 반복문으로 구현

T = int(input())
for tc in range(1, T + 1):

    N = int(input())
    checked = [[0] * N for _ in range(N)]
    board = [list(map(int, list(input()))) for _ in range(N)]

    for i in range(N):
        for j in range(N):
            if board[i][j] == 2:
                start = (i, j)
            elif board[i][j] == 3:
                end = (i, j)
            elif board[i][j] == 1:
                checked[i][j] = 1

    stack = []
    #우하좌상
    dx = [1, 0, -1, 0]
    dy = [0, 1, 0, -1]

    #DFS 구현
    stack = [start]

    boolean = False
    while stack:
        v = stack.pop()
        y = v[0]
        x = v[1]
        checked[y][x] = 1
        if checked[end[0]][end[1]]:
            boolean = True
            break
        #2차원배열 index조건
        for i in range(4):
            if 0 <= y + dy[i] < N and 0 <= x + dx[i] < N and checked[y + dy[i]][x + dx[i]] == 0:
                stack.append((y + dy[i], x + dx[i]))

    #출력
    if boolean:
        print('#{} {}'.format(tc, 1))
    else:
        print('#{} {}'.format(tc, 0))

1-2. 스택없는 재귀 dfs로 구현 (지나간 길은 1로 바꾸어준다.)

# 스택 없는 dfs 재귀로 구현
def dfs(si,sj):
    global result
    for i in range(4):
        if si+di[i] in range(N) and sj+dj[i] in range(N):
            if load[si + di[i]][sj + dj[i]] == 3:
                result = 1
                return
            if load[si + di[i]][sj + dj[i]] == 0:
                load[si + di[i]][sj + dj[i]] = 1
                dfs(si + di[i], sj + dj[i])


for tc in range(1,int(input())+1):
    N = int(input())
    load=[]
    for _ in range(N):
        load.append(list(map(int,input())))

    for i in range(N):
        for j in range(N):
            if load[i][j]==2:
             si,sj=i,j

    di = [0,0,-1,1]
    dj = [1,-1,0,0]
    result = 0
    dfs(si,sj)

    print("#{} {}".format(tc,result))

2. 스택 사용하지않고 반복문과 재귀식만으로 구현 (스택.pop()대신 좌표를 감소시킴)

# 스택없이 반복문과 재귀함수 사용
def check_route(board, cnt_r, cnt_c):

    # 상하좌우 순서로 탐색
    for i in range(4):
        cnt_r += dr[i]
        cnt_c += dc[i]

        # 탐색 위치의 인덱스가 유효하다면
        if 0 <= cnt_r < N and 0 <= cnt_c < N:
            # 도착점을 찾으면 True를 리턴한다.
            if board[cnt_r][cnt_c] == 3:
                return True
            # 현재위치가 0 이고 아직 방문하지 않았다면
            elif (board[cnt_r][cnt_c] == 0 and not visited[cnt_r][cnt_c]):
                # 방문표시하고 해당 위치에서 다시 탐색을 진행한다.
                visited[cnt_r][cnt_c] = True
                if check_route(board, cnt_r, cnt_c):
                    return True
        # 탐색 종료 후에는 기존 위치로 복귀한다.
        cnt_r -= dr[i]
        cnt_c -= dc[i]

    # 탐색을 마쳤는데 도착점을 찾지 못했다면 False를 리턴한다.
    # 재귀함수 였다면, 재귀함수 위치로 돌아간다.
    return False


T = int(input())
for tc in range(1, T+1):
    N = int(input())
    board = [list(map(int, input())) for _ in range(N)]

    # 시작위치 설정
    for i in range(N):
        for j in range(N):
            if board[i][j] == 2:
                cnt_r = i
                cnt_c = j

    # 델타탐색 초기값 설정한다.
    dr = [-1, 1, 0, 0]
    dc = [0, 0, -1, 1]

  	# 방문기록
    visited = [[False] * N for _ in range(N)]

    result = check_route(board, cnt_r, cnt_c)
    print("#{} {}".format(tc, int(result)))

다양한 코드 출처 : SSAFY 6기 서울3반

댓글