출처: https://bumcrush.tistory.com/182 [맑음때때로 여름]

상세 컨텐츠

본문 제목

백준 3055 탈출(bfs)

알고리즘

by 장동균 2020. 8. 14. 23:37

본문

https://www.acmicpc.net/problem/3055

 

3055번: 탈출

문제 사악한 암흑의 군주 이민혁은 드디어 마법 구슬을 손에 넣었고, 그 능력을 실험해보기 위해 근처의 티떱숲에 홍수를 일으키려고 한다. 이 숲에는 고슴도치가 한 마리 살고 있다. 고슴도치��

www.acmicpc.net

#include <iostream>
#include <queue>
#include <algorithm>

using namespace std;

const int MAX = 50;

typedef struct
{
    int x, y;
} Water;

typedef struct
{
    int x, y;
} Dir;

typedef struct
{
    int x, y, cnt;
} HedgeHog;

Dir dirMove[4] = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
queue<Water> q;
string graph[MAX];
int R, C;
int start_X, start_Y, end_X, end_Y;
bool visited[MAX][MAX];
// bool waterVisited[MAX][MAX];
int waterDay[MAX][MAX];

void flood()
{
    waterDay[end_X][end_Y] = 2500;
    for (int i = 0; i < R; i++)
    {
        for (int j = 0; j < C; j++)
        {
            if (graph[i][j] == '*')
            {
                q.push({i, j});
                // waterVisited[i][j] = true;
            }
        }
    }
    while (!q.empty())
    {
        int curX = q.front().x;
        int curY = q.front().y;
        q.pop();
        for (int i = 0; i < 4; i++)
        {
            int nextX = curX + dirMove[i].x;
            int nextY = curY + dirMove[i].y;
            if (0 <= nextX && nextX < R && 0 <= nextY && nextY < C && graph[nextX][nextY] == '.' && !waterDay[nextX][nextY])
            {
                waterDay[nextX][nextY] = waterDay[curX][curY] + 1;
                // waterVisited[nextX][nextY] = true;
                q.push({nextX, nextY});
            }
        }
    }
}
int bfs(int x, int y, int cnt)
{
    queue<HedgeHog> p;

    p.push({x, y, cnt});
    visited[x][y] = true;
    while (!p.empty())
    {
        int curX = p.front().x;
        int curY = p.front().y;
        int curCnt = p.front().cnt;
        // cout<<curX<<" "<<curY<<" "<<curCnt<<"\n";
        p.pop();
        if (curX == end_X && curY == end_Y)
        {
            return curCnt;
        }
        for (int i = 0; i < 4; i++)
        {
            int nextX = curX + dirMove[i].x;
            int nextY = curY + dirMove[i].y;
            if (0 <= nextX && nextX < R && 0 <= nextY && nextY < C && !visited[nextX][nextY])
            {

                if (graph[nextX][nextY] == '.' || graph[nextX][nextY] == 'D')
                {
                    if (curCnt + 1 < waterDay[nextX][nextY] || waterDay[nextX][nextY] == 0)
                    {
                        p.push({nextX, nextY, curCnt + 1});
                        visited[nextX][nextY] = true;
                    }
                }
            }
        }
    }
    return 0;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cin >> R >> C;

    for (int i = 0; i < R; i++)
    {
        cin >> graph[i];
    }
    for (int i = 0; i < R; i++)
    {
        for (int j = 0; j < C; j++)
        {
            if (graph[i][j] == 'S')
            {
                start_X = i;
                start_Y = j;
                // graph[i][j]='.';
            }
            if (graph[i][j] == 'D')
            {
                end_X = i;
                end_Y = j;
            }
        }
    }
    flood();
    // for(int i=0;i<R;i++){
    //     for(int j=0;j<C;j++){
    //         cout<<waterDay[i][j]<<" ";
    //     }
    //     cout<<"\n";
    // }
    int ans = bfs(start_X, start_Y, 0);
    if (!visited[end_X][end_Y])
        cout << "KAKTUS";
    else
    {
        cout << ans;
    }
}

//이거 풀리면 불! 문제 풀어보자

이 문제를 푸는데 정말 오랜 시간이 걸렸다.

 

최단거리를 구할 때는 반드시 bfs로 풀어야 한다는 것을 알면서도 dfs로 만들었다. 

 

void dfs(int x, int y, int cnt) {
    visited[x][y]=true;
    if (x==end_X&&y==end_Y) {
        ans.push_back(cnt);
        return;
    }
    for (int i=0;i<4;i++) {
        int nextX=x+dirMove[i].x;
        int nextY=y+dirMove[i].y;
        if (0<=nextX&&nextX<R&&0<=nextY&&nextY<C&&!visited[nextX][nextY]) {
            if (graph[nextX][nextY]=='.'||graph[nextX][nextY]=='D') {
                for (int i=0;i<R;i++) {
                    tmpGraph[i]=graph[i];
                }
                bfs();
                dfs(nextX, nextY, cnt+1);
                for (int i=0;i<R;i++) {
                    graph[i]=tmpGraph[i];
                }
            }
        }
        //최단거리를 찾는거니까 이 부분도 bfs와 같이 구현해주어야 하는것 같은데......
    }
}

이렇게 해도 테스트 케이스들은 모두 통과한다. 내 생각에는 이렇게 하면 도착지점에 도착하는 모든 경우의 수들이 vector ans 속에 들어갈 것이라 생각했지만, 처음 dfs를 돌 때 visited가 true가 돼서 사실상 저 vector 속에 들어가게 되는 답안은 단 하나뿐이게 된다. 때문에 dfs로 최단거리 문제를 접근해서는 안되는 것이다.

 

그 이후 bfs 식으로 코드를 구성하였지만 그럼에도 계속해서 '메모리 초과' 오류가 났다. 이 오류의 이유를 찾는데 정말 많은 시간이 들었다.

 

메모리 초과가 발생한 이유는 bfs내에서 return 0를 하지 않았기 때문이다..... 도착하지 못하는 경우가 분명히 생기는데 이때는 return 0 구문을 빼먹으면 return 값이 없게 된다. 정말 많이 삽질했다.....

관련글 더보기

댓글 영역