#4963

zzwwoonn·2022년 5월 1일
0

Algorithm

목록 보기
7/71

randMap = []
visitMap = []
cnt = 0

def inputSize():
    a, b = map(int, input().split())
    return a, b

def makeMap(col, row):
    global cnt
    randMap.clear()
    visitMap.clear()
    cnt = 0
    for j in range(0, row):
        randMap.append(list(map(int, input().split())))
    for j in range(0, row):
        visitMap.append([0] * col)

def dfs(row, col):
    # input()
    # print("dfs 입장, row = ", row, ", col = ", col)
    if col < 0 or row < 0 or col >= len(randMap[0]) or row >= len(randMap):
        # print("범위 넘어갔어, 나가")
        return 0

    if visitMap[row][col] == 1:
        # print("이미 방문한 곳이야, 나가")
        return 0
    
    visitMap[row][col] = 1
    # print("처음 왔어 방문 체크 ", "visitMap[",row, "][", col, "]", "=", visitMap[row][col])
    # 이미 온 곳도 아니고 범위도 맞다 => 방문했다고 체크

    if(randMap[row][col] == 1):
        # 온 곳이 땅이 맞으면
    
        # print("12시 방문")
        dfs(row-1, col) 

        # print("1-2시 방문")
        dfs(row-1, col+1) 

        # print("3시 방문")
        dfs(row, col+1) 

        # print("4-5시 방문")
        dfs(row+1, col+1)

        # print("6시 방문")
        dfs(row+1, col)
        
        # print("7-8시 방문")
        dfs(row+1, col-1)

        # print("9시 방문")
        dfs(row, col-1)  

        # print("10-11시 방문")
        dfs(row-1, col-1)


def main():
    while(1):
        col, row = inputSize()
        if col == 0 and row == 0:
            return
        global cnt
        makeMap(col, row)

        for i in range(0, row):
            for j in range(0, col):
                if(visitMap[i][j] == 1 or randMap[i][j] == 0): 
                    # 방문 한 곳(발자국이 있거나)이거나 바다면 거기서 시작도 안해( 발잦국을 찍을 수 있는 가능성이 없어)
                    continue 
                cnt += 1
                # 시작하는, 발 딛고 있는 그 부분은 무조건 섬이라는 가정으로 시작
                dfs(i, j)
                # 갈 수 있는 곳은 다 가면서 발자국을 찍어
                
        print(cnt)
main()

사각형 폼이 주어지고 바다와 육지의 경계가 입력으로 주어진다. 육지로 시작해서 걸어갈 수 있는 곳까지 걸어갔다가(육지가 아닌 바다이거나 범위를 벗어나는 곳은 가지 않는다, 갈 수 있는 끝까지 가본다) 다시 돌아와야 하므로 DFS 임을 떠올렸다.

DFS 구현까지는 성공했으나 cnt(총 육지의 개수 세기)를 어디에 놔둬야 하지?를 생각해내는데 시간이 너무 오래 걸려 정현이 형한테 도움을 받았다.

cnt는 칸 수마다 dfs를 돌리고 나왔을 때 cnt를 하나 증기시켜주면 되는데 이 때 가장 중요한 핵심은 "지금 서있는 이곳이 육지의 시작이고 무조건 섬이다" 라는 개념이다. 어차피 육지로 체크를 해두고 안으로 들어가도 방문한 곳은 체크를 해놓을 것이고 육지가 아닌 곳은 dfs 안에서도, dfs를 출발점을 정할 때도 전혀 갈 필요가 없기 때문이다.

dfs를 돌리기 전에 cnt += 1을 해줘도 되고 dfs 한 바퀴 끝나고 나서 cnt += 1 을 해줘도 된다. dfs 안으로 들어가면 밟고 있는 곳 부터 상하좌우, 대각선까지 갈 수 있는 최대로 걸어가본다. 이 때 이미 가봤던 곳이거나 범위를 벗어나면 return으로 빠져 나온다. 그러고 (시계로 비유를 들면) 12시 1-2시 3시 4-5시 6시~~ 10-11시 까지 순서대로 dfs를 돌려준다.

이 때 시간 복잡도는 총 O(M*N) 이다. (M=width, N=height)
왜냐하면 한번 방문했던 칸은 방문하지 않는다고 했을 때도 모든 칸을 적어도 한번씩은 가야하기 때문이다.

0개의 댓글