알고리즘/백준

백준 2667번 - 단지번호붙이기 / Python

Hwisaek 2021. 9. 20. 00:59
반응형

문제: https://www.acmicpc.net/problem/2667

 

2667번: 단지번호붙이기

<그림 1>과 같이 정사각형 모양의 지도가 있다. 1은 집이 있는 곳을, 0은 집이 없는 곳을 나타낸다. 철수는 이 지도를 가지고 연결된 집의 모임인 단지를 정의하고, 단지에 번호를 붙이려 한다. 여

www.acmicpc.net

문제 설명

더보기

문제

<그림 1>과 같이 정사각형 모양의 지도가 있다. 1은 집이 있는 곳을, 0은 집이 없는 곳을 나타낸다. 철수는 이 지도를 가지고 연결된 집의 모임인 단지를 정의하고, 단지에 번호를 붙이려 한다. 여기서 연결되었다는 것은 어떤 집이 좌우, 혹은 아래위로 다른 집이 있는 경우를 말한다. 대각선 상에 집이 있는 경우는 연결된 것이 아니다. <그림 2>는 <그림 1>을 단지별로 번호를 붙인 것이다. 지도를 입력하여 단지수를 출력하고, 각 단지에 속하는 집의 수를 오름차순으로 정렬하여 출력하는 프로그램을 작성하시오.

입력

첫 번째 줄에는 지도의 크기 N(정사각형이므로 가로와 세로의 크기는 같으며 5≤N≤25)이 입력되고, 그 다음 N 줄에는 각각 N개의 자료(0 혹은 1)가 입력된다.

출력

첫 번째 줄에는 총 단지수를 출력하시오. 그리고 각 단지내 집의 수를 오름차순으로 정렬하여 한 줄에 하나씩 출력하시오.


정답

from collections import deque

n = int(input())

array = [list(input()) for _ in range(n)]
visited = [[False] * n for _ in range(n)]

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

counts = []
q = deque()
for a in range(n):
    for b in range(n):
        if array[a][b] == '1':
            q.append((a, b))
            count = 1 if array[a][b] == '1' and not visited[a][b] else 0
            visited[a][b] = True

            while q:
                x, y = q.pop()

                for i in range(4):
                    nx, ny = x + dx[i], y + dy[i]
                    if -1 < nx < n and -1 < ny < n:
                        if not visited[nx][ny] and array[nx][ny] == '1':
                            q.append((nx, ny))
                            visited[nx][ny] = True
                            count += 1

            if count != 0:
                counts.append(count)

print(len(counts))

for count in sorted(counts):
    print(count)


풀이

  BFS 혹은 DFS를 이용하여 탐색한 다음 단지의 수, 단지 내 집의 수를 구하는 문제입니다.

 

 처음에는 DFS를 재귀를 이용하여 풀었습니다.

 

n = int(input())

array = [list(input()) for _ in range(n)]
visited = [[False] * n for _ in range(n)]

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

group = 0
counts = []
for a in range(n):
    for b in range(n):

        count = 0


        def dfs(x, y):
            global array
            global count
            global visited

            if visited[x][y]:
                return

            visited[x][y] = True
            if array[x][y] == '0':
                return

            count += 1

            for i in range(4):
                nx = x + dx[i]
                ny = y + dy[i]
                if -1 < nx < n and -1 < ny < n and not visited[nx][ny] and array[nx][ny] == '1':
                    dfs(nx, ny)


        dfs(a, b)
        if count != 0:
            group += 1
            counts.append(count)

print(group)

for count in sorted(counts):
    print(count)

 

 재귀를 이용하여 해결하는 것은 시간과 메모리는 더 효율적이나 코드가 복잡하다는 단점이 있습니다. 그래서 BFS를 이용하여 풀던 중 유용한 방법이 생각났습니다.

 

 다른 언어를 이용하여 문제를 풀더라도 DFS는 재귀가 아닌 스택을 이용하여 풀 수 있으며, BFS는 큐를 이용하여 처리를 한다는 것입니다. 근데 파이썬은 스택과 큐를 합친 deque를 이용할 수 있는데, 이를 이용하면 pop(), popleft()를 변경함으로써 BFS와 DFS를 간단히 왔다 갔다 할 수 있다는 것을 깨달았습니다. 이 문제를 시작으로 BFS와 DFS를 간단히 변환하기 위해 앞으로 deque를 이용하여 모든 탐색 문제를 해결해보겠습니다. 

반응형