[Baekjoon,3109] 빵집

1 분 소요

초기에 모든 경로를 DFS를 이용하며 만들었고 다음 두 가지의 경우에 따라 방문 여부를 표시했다.

  • 경로를 완성한 경우 : 방문해온 지점을 표시한다.
  • 경로 완성을 실패한 경우 : 방문해온 표시를 해제한다.

이러한 방법은 이전에 실패했던 경로를 다시 방문하여 총 $R$개의 출발 지점에 대해 시간복잡도가 $O(R\times 3^C)$로 시간초과가 난다.
그런데 방금 말했듯이 DP처럼 이전에 시도하다 실패한 지점을 다시 방문하지 않으면 해결할 수 있지 않을까? 어짜피 다시 이곳을 다른 경로를 통해 방문한다고 해도 실패할 것이 뻔하기 때문이다. 이는 경로 완성을 실패한 지점 또한 다시 방문 하지 않도록 하여 구현할 수 있다.

구현

이에 대한 구현을 아래에서 볼 수 있다. 추가적으로 시작, 도착 파이프 라인 위치에 한 칸씩 띄어 탐색을 하고 있는 것을 볼 수 있다. 파이프 라인을 한 칸 띄운다고 해도 충분히 도달 가능하기 때문이다.

#include <iostream>
#include <vector>
#include <cstring>
using namespace std;

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

int r,c;
vector<string> board;
bool visited[10000][500];

// 범위를 확인한다. 
inline bool inRange(int y, int x)
{
    return 0<=y && y<r && 0<=x && x<c;
}

bool dfs(int y, int x)
{
    if(visited[y][x] || board[y][x]=='x')
        return false;
    visited[y][x]=true;
    // 경로가 완성된 경우 
    if(x==c-2)
        return true;
    
    // 세 가지 방향에 대해 탐색한다. 
    for(int i=0;i<3;++i)
    {
        int ny=y+dy[i];
        int nx=x+1;
        // 하나라도 완성되면 바로 반환한다. 
        if(inRange(ny,nx) && dfs(ny,nx))
            return true;
    }
    // 표시를 해제하지 않는다!!
    // visited[y][x]=false;
    return false;
}

int solve()
{
    int ret=0;
    memset(visited,false,sizeof(visited));
    // 모든 출발 지점에서 탐색을 시작한다. 
    for(int i=0;i<r;++i)
        if(board[i][1]=='.')
            ret+=dfs(i,1);
    
    return ret;
}

int main()
{
    cin>>r>>c;
    board=vector<string>(r);
    for(int i=0;i<r;++i)
        cin>>board[i];
    
    cout<<solve()<<endl;
    
    return 0;
}

댓글남기기