BOJ 5022

연결

문제출처

문제 해석

  • 주어지는 좌표 A1,A2와 B1,B2를 각각 모두 연결할 수 있는지 구하는 문제입니다.
  • 만약 연결이 가능하면 연결하기 위한 최소 길이를 구해야 합니다.

설계(20)

  • 가능한 연결 순서를 모두 탐색해야하는 bfs 문제입니다.
  • 가능한 연결순서는 아래와 같습니다.
    1. A1,A2연결 후, B1,B2연결
    2. B1,B2연결 후, A1,A2연결
  • 먼저 연결할 두개의 좌표를 이용하여 연결함과 동시에, path배열에 경로를 저장합니다.
  • 첫번째 연결이 끝난 후, 방문표시를 초기화 해주고 path경로를 따라 방문처리를 해줍니다.
  • 다음으로, 다른 두개의 좌표를 연결합니다.
  • 연결이 되지 않는 좌표들의 경우 길이를 INF로 설정하여 구분할 수 있게 하였습니다.
  • 가능한 연결순서를 모두 탐색하여 그 중, 최소길이를 갱신해줍니다.
  • 총 bfs탐색을 4번 하면 원하는 값을 얻을 수 있습니다.O(NM)

구현(60)

코드
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;

#define MAXN 101
#define INF 987654321

int path[MAXN*MAXN];

pair<int,int> coord[4];
bool visited[MAXN][MAXN];
int N,M;

int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};
int ans = INF;
queue<pair<int,int> > q;
int bfs(pair<int,int> A, pair<int,int> B, pair<int,int> C, pair<int,int> D){
    q.push(A);
    visited[A.first][A.second] = true;
    int cnt = 0;
    while (!q.empty()){
        int q_size = q.size();
        while (q_size--){
            int x = q.front().first;
            int y = q.front().second;
            q.pop();
            if (x == B.first && y == B.second) return cnt;
            for (int k =0 ;k< 4; k++){
                int nx = x + dx[k];
                int ny = y + dy[k];
                if (nx < 0 || ny < 0 || nx>N || ny>M) continue;
                if (nx == C.first && ny == C.second) continue;
                if (nx == D.first && ny == D.second) continue;
                if (visited[nx][ny]) continue;
                visited[nx][ny] = true;
                path[nx*(M+1)+ny] = x*(M+1)+y;
                q.push({nx,ny});
            }
        }
        cnt++;
    }
    return INF;
}

void Init(){
    memset(path,-1,sizeof(path));
    memset(visited,false,sizeof(visited));
    while (!q.empty()) q.pop();
}
void check_path(pair<int,int> coord){
    memset(visited,false,sizeof(visited));
    while (!q.empty()) q.pop();
    int x = coord.first;
    int y = coord.second;
    int target = x*(M+1)+y;
    while (path[target]!= -1){
        visited[target/(M+1)][target%(M+1)] = true;
        target = path[target];
    }
    visited[target/(M+1)][target%(M+1)] = true;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    memset(path,-1,sizeof(path));
    cin >> M >> N;
    for (int i = 0;i < 4;i++){
        cin >> coord[i].second >> coord[i].first;
    }
    int sum1 = bfs(coord[0],coord[1],coord[2],coord[3]);
    check_path(coord[1]);
    int sum2 = bfs(coord[2],coord[3],coord[0],coord[1]);
    if (max(sum1,sum2)!= INF) ans = min(ans,sum1+sum2);
    Init();
    sum1 = bfs(coord[2],coord[3],coord[0],coord[1]);
    check_path(coord[3]);
    sum2 = bfs(coord[0],coord[1],coord[2],coord[3]);
    if (max(sum1,sum2)!= INF) ans = min(ans,sum1+sum2);

    if (ans ==INF) cout <<"IMPOSSIBLE\n";
    else cout << ans <<"\n";
    return 0;
}
디버깅
  • bfs함수를 구현할 때, 다른 좌표들을 고려하지 않아서 WA가 나왔습니다. 매개변수를 두개 더 추가하여, 다른 좌표들을 만날경우 큐에 추가하지 않도록 하였습니다.
  • N,M의 최대범위는 100이지만, 좌표가 100까지 쓰이기 때문에 최대 범위를 101로 설정해야 했습니다. 이를 제대로 구현하지 않아서 런타임에러가 났습니다.
  • 가능한 연결순서에서, 1번의 경우를 모두 탐색한 후에 path를 -1로 갱신시키지 않는 실수를 하였습니다.
  • 디버깅을 할때, 위의 경우들을 제대로 체크하지 못하여 NCPC2010에서 제공하는 testcase를 참조하여 디버깅하였습니다.
제출결과
  • 0 ms

마무리

  • bfs응용문제입니다. 정답률이 아주 낮은 이유가 있었던 문제입니다. 대회에서 제공하는 testcase를 참조해서 디버깅을 하였는데, 1by1으로 디버깅을 하느라 시간이 너무 오래걸렸습니다.
  • 디버깅시간을 줄이고, 설계를 더욱 견고하게 해야 할 것 같습니다.