강의

멘토링

로드맵

Inflearn brand logo image

인프런 커뮤니티 질문&답변

김팥죽님의 프로필 이미지
김팥죽

작성한 질문수

10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트

3-L

3-L DFS 재귀 vs. 반복문

해결된 질문

작성

·

58

0

안녕하세요, 큰돌님. 강의 잘 듣고 있습니다.

 

DFS 재귀 vs. 반복문 구현 방법을 결정하는 기준에 대해 여쭙고 싶습니다.

 

제가 현재 고민중인 접근 방식은 다음과 같습니다:

1. 완전 탐색(완탐) 문제의 경우 일단 재귀로 구현

2. 엣지 케이스 테스트 시 메모리 초과(Memory Overflow) 또는 시간 초과(Time Overflow)가 발생하면 반복문으로 변경

 

코딩 테스트(코테)의 경우, 위와 같은 접근 방식이 적절할 지 조언을 부탁드리겠습니다.


재귀로 풀면 쉽게 풀리는 걸 알았지만 DFS를 반복문으로 구현하면 디버깅이나 메모리 측면에서 유리하다고 알고 있어, 이번 문제를 오기로 반복문으로 접근하여 풀고자 했습니다.

 

그러나 결과적으로 재귀로 작성한 코드보다 성능이 낮게 측정되었습니다. 여러 최적화 끝에 다음과 같은 코드를 작성했는데, 큰돌님께서 작성하신 코드보다 메모리를 4KB 더 소모하고, 실행 시간이 26ms 더 느리게 측정되었습니다.

 

테스트 케이스에 따라 제 코드가 더 빠르게 동작할 수도있겠지만 결과적으로, 어떤 문제는 반복문으로, 어떤 문제는 재귀로 풀어야 적절할지 를 어떻게 결정하지? 가 의문으로 남아 질문드립니다!

 

#include <bits/stdc++.h>
using namespace std;

const int dy[4] = {1, 0, -1, 0};
const int dx[4] = {0, 1, 0, -1};

int R, C;
int grid[20][20];

inline bool is_valid(int y, int x) {
  return (0 <= y && y < R && 0 <= x && x < C);
}

int iterative_dfs() {
  stack<tuple<int, int, int, int>> st;

  int startMask = (1 << grid[0][0]);
  st.push({0, 0, 1, startMask});

  int maxDepth = 0;

  while (!st.empty()) {
    auto [y, x, depth, used] = st.top();
    st.pop();

    maxDepth = max(maxDepth, depth);

    for (int i = 0; i < 4; i++) {
      int ny = y + dy[i];
      int nx = x + dx[i];
      if (!is_valid(ny, nx))
        continue;

      int alpha = grid[ny][nx];
      if (used & (1 << alpha))
        continue;

      int nextUsed = used | (1 << alpha);
      st.push({ny, nx, depth + 1, nextUsed});
    }
  }
  return maxDepth;
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  cin >> R >> C;
  for (int i = 0; i < R; i++) {
    for (int j = 0; j < C; j++) {
      char tmp_c;
      cin >> tmp_c;
      grid[i][j] = tmp_c - 'A';
    }
  }

  cout << iterative_dfs() << "\n";
  return 0;
}

답변 1

1

큰돌님의 프로필 이미지
큰돌
지식공유자

안녕하세요 팥죽님 ㅎㅎ

DFS 재귀 vs. 반복문 구현 방법을 결정하는 기준에 대해 여쭙고 싶습니다.

 

1. 완전 탐색(완탐) 문제의 경우 일단 재귀로 구현

-> 완탐의 경우도 반복문으로도 쉽게 풀리는 경우가 많습니다. 반복문 -> 재귀로 시도해주세요.

 

DFS를 반복문으로 구현하면 디버깅이나 메모리 측면에서 유리하다고 알고 있어, 이번 문제를 오기로 반복문으로 접근하여 풀고자 했습니다.

-> 풀이를 보면 이건 반복문이 아니라 BFS에 가깝습니다.

  while (!st.empty()) {
    auto [y, x, depth, used] = st.top();
    st.pop();

    maxDepth = max(maxDepth, depth);

queue를 기반으로 top, pop으로 앞부분부터 처리하는 BFS에 가깝습니다.

 

이 문제의 지문을 볼까요?

첫째 줄에 말이 지날 수 있는 최대의 칸 수를 출력한다.


-> 최대의 칸이고 한 칸당 4가지 경우의 수가 있고 -> 무식하게 풀자면 -> 완전탐색으로 모든 경우의 수를 탐색해야 하는 것을 알 수 있습니다.

이 때 각 칸마다 4개의 경우의 수를 생각하며 뻗어나가야 하는데 이를 -> 단순히 for문이나 while문으로 풀기에는 버겁죠. 이 때는 재귀를 사용해야 합니다.

 

 



또 질문 있으시면 언제든지 질문 부탁드립니다.

좋은 수강평과 별점 5점은 제게 큰 힘이 됩니다. :)

감사합니다.

강사 큰돌 올림.


김팥죽님의 프로필 이미지
김팥죽

작성한 질문수

질문하기