본문 바로가기
코딩테스트/이코테

[CH5 DFS/BFS] 음료수 얼려 먹기

by 의정부핵꿀밤 2021. 12. 25.
728x90

문제 설명

  • NXM 크기의 얼음 틀이 있다
  • 구멍이 뚫려 있는 부분은 0, 칸막이가 존재하는 부분은 1로 표시된다
  • 구멍이 뚫려 있는 부분끼리 상, 하, 좌, 우로 붙어 있는 경우 서로 연결되어 있는 것으로 간주한다
  • 이 때 얼음 틀의 모양이 주어졌을 때 생성되는 총 아이스크림의 개수를 구하는 프로그램을 작성하시오
  • 다음의 4X5 얼음 틀 예시에서는 아이스크림이 총 3개 생성된다

4X5 얼음틀

 

입력 조건

  • 첫번째 줄에 얼음 틀의 세로 길이 N과 가로 길이 M이 주어진다 (1 <= N, M <= 1000)
  • 두번째 줄부터 N+1번째 줄까지 얼음 틀의 형태가 주어진다
  • 이 때 구멍이 뚫려있는 부분은 0, 그렇지 않은 부분은 1이다

 

출력 조건

  • 한 번에 만들 수 있는 아이스크림의 개수를 출력한다

[풀이]

이 문제는 DFS로 해결할 수 있다

앞에서 배운대로 얼음틀이 상하좌우로 연결되어 있다고 포함할 수 있으므로 그래프 형태로 모델링할 수 있다

 

예를 들어 3X3 크기의 얼음 틀이 있다고 가정하면 아래와 같이 모델링할 수 있다

3X3 그래프 모델링

0인 값이 상하좌우로 연결된 노드를 묶으면 위처럼 총 3개의 묶음이 나오게 된다

이 묶음을 찾아주는 프로그램을 DFS를 통해 작성하면 되는 것이다!

 

<작성 순서>

  1. 특정한 지점의 주변 상, 하, 좌, 우를 살펴본 뒤에 주변 지점 중에서 값이 0이면서 아직 방문하지 않은 지점이 있다면 해당 지점을 방문한다
  2. 방문한 지점에서 다시 상, 하, 좌, 우를 살펴보면서 방문을 다시 진행하면, 연결된 모든 지점을 방문할 수 있다
  3. 1, 2번의 과정을 모든 노드에 반복하며 방문하지 않은 지점의 수를 센다

파이썬 코드)

#n, m을 공백으로 구분하여 입력받기
n, m = map(int, input().split())

#2차원 리스트의 맵 정보 입력받기
graph=[]
for i in range(n):
    graph.append(list(map(int, input().split())))

#DFS로 특정한 노드를 방문한 뒤에 연결된 모든 노드들도 방문
def dfs(x,y):
    #주어진 범위를 벗어나는 경우에는 즉시 종료
    if x <= -1 or x >= n or y <= -1 or y >= m:
        return False

    #현재 노드를 아직 반문하지 않았다면
    if graph[x][y]==0:
        #해당 노드 방문 처리
        graph[x][y]=1
        #상, 하, 좌, 우의 위치도 모두 재귀적으로 호출
        dfs(x-1, y) #상
        dfs(x+1, y) #하
        dfs(x, y-1) #좌
        dfs(x, y+1) #우
        return True
    return False

#모든 노드(위치)에 대하여 음료수 채우기
result=0
for i in range(n):
    for j in range(m):
        #현재 위치에서 dfs 수행
        if dfs(i,j) == True:
            result += 1

print(result)

작성하고 보면 쉬운데 작성하는 과정이 어려운 것 같다

이번에도 책의 코드를 참고해가며 풀었다,,

어느 지점에서 재귀호출을 하고 어떻게 구상할지 고민하는게 어렵다ㅠㅠ

하다보면 늘겠지!

파이썬 결과화면

 

 

C++ 코드)

#include <iostream>
using namespace std;

int n,m;
int graph[1000][1000];

// DFS로 특정한 노드를 방문한 뒤에 연결된 모든 노드들도 방문
bool dfs(int x, int y)
{
    //주어진 범위를 벗어나는 경우에는 즉시 종료
    if(x<=-1 || x>=n || y<=-1 || y>=m) 
    {
        return false;
    }
    //현재 노드를 아직 방문하지 않았다면
    if(graph[x][y]==0)
    {
        //현재 노드 방문 처리
        graph[x][y]=1;
        //상하좌우의 위치도 모두 재귀적으로 호출
        dfs(x-1, y);
        dfs(x+1, y);
        dfs(x, y-1);
        dfs(x, y+1);
        return true;
    }
    return false;
}

int main()
{
    int result=0;
    // N, M을 공백을 기준으로 구분하여 입력 받기
    cin>>n>>m;
    // 2차원 리스트의 맵 정보 입력 받기
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            cin>>graph[i][j];
        }
    }
    
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(dfs(i,j)==true)
            {
                result++;
            }
        }
    }

    cout<<result;
    return 0;
}

c++에서는 graph와 n, m변수를 전역변수로 선언해서 사용하였다

 

c++ 결과화면


더 많은 문제를 풀어서 dfs와 bfs를 정복하다 못해 아주 찢고 싶다!!!

크리스마스에도 코딩이지! 화이팅!

728x90

댓글