[BOJ] 1035 조각 움직이기

2025. 9. 17. 12:06·백준 문제풀이/dfs

문제 요약

문제 링크: 백준 1035 - 조각 움직이기

문제 설명

 


접근 방법

5X5 크기의 고정된 판에서 최대 5개의 조각의 모든 움직임 경우의 수를 구해준다. N이 크지 않아서 완전탐색 방법으로 해결하고자 시도했었다.

첫 번째 풀이로는 dfs로 조각이 이동할 수 있는 모든 경우의 수를 계산하여 그때, 조각끼리 연결되어 있다면,  조각들의 이동 값 중에서 가장 작은 값을 정답으로 저장할 수 있게 구현했다. 최적화 없는 이 방식으로도 통과가 되긴 했지만, 필자의 코드가 다른 코드들보다 실행시간이 유독 길었다.

 

따라서 두 번째 풀이에선 첫 번째 풀이에서 중복된 움직임 경우의 조각은 판단하지 않게 map을 활용했다. 5X5 보드를 uint32_t로 비트연산한 결과를 map에 저장하여 중복 탐색을 방지할 수 있었다. 

uint32_t getState() {
    uint32_t state = 0;
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            if (mat[i][j] == '*') {
                int idx = i * 5 + j;
                state |= (1u << idx);
            }
        }
    }
    return state;
}

코드

비트 연산없이 완전탐색으로만 통과 (120ms)

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

int ans = 1e9;
char mat[6][6];
bool vis[6][6];
int d[4][2] = { {0,1},{0,-1},{1,0},{-1,0} };
vector<pair<int, int>>v;

bool check() {
    bool bfs[6][6];
    int y, x;
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            if (mat[i][j] == '*') {
                y = i;
                x = j;
            }
            bfs[i][j] = 0;
        }
    }
    queue<pair<int, int>>q;
    int count = 1;
    q.push({ y,x });
    bfs[y][x] = 1;
    while (q.size()) {
        int yy = q.front().first;
        int xx = q.front().second;
        q.pop();
        if (count == v.size())
            return 1;
        for (int i = 0; i < 4; i++) {
            int dy = yy + d[i][0];
            int dx = xx + d[i][1];
            if (dy >= 5 || dy < 0 || dx >= 5 || dx < 0)
                continue;
            if (bfs[dy][dx])
                continue;
            if (mat[dy][dx] == '*') {
                q.push({ dy,dx });
                bfs[dy][dx] = 1;
                count++;
            }
        }
    }
    return 0;
}

void dfs(int idx, int cnt) {
    if (idx == v.size()) {
        if (check())
            ans = min(ans, cnt);
        return;
    }
    if (cnt >= ans)  // 유망하지 않은 경우에는 탐색 X, 이 한줄로 실행시간이 많이 줄어들었다.
        return;
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            if (!vis[i][j]) {
                vis[i][j] = 1;
                mat[i][j] = '*';
                int dis = abs(v[idx].first - i) + abs(v[idx].second - j);
                dfs(idx + 1, cnt + dis);
                mat[i][j] = '.';
                vis[i][j] = 0;
            }
        }
    }
}

void solve() {
    dfs(0, 0);
    cout << ans;
}

void input() {
    for (int i = 0; i < 5; i++) {
        cin >> mat[i];
        for (int j = 0; j < 5; j++) {
            if (mat[i][j] == '*') {
                v.push_back({ i,j });
                mat[i][j] = '.';
            }
        }
    }
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    input();
    solve();
}

 

비트연산으로 중복된 탐색을 제거 (128ms)

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

int ans = 1e9;
char mat[6][6];
bool vis[6][6];
int d[4][2] = { {0,1},{0,-1},{1,0},{-1,0} };
vector<pair<int, int>>v;
unordered_map<uint32_t,int>st;

bool check() {
    bool bfs[6][6];
    int y, x;
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            if (mat[i][j] == '*') {
                y = i;
                x = j;
            }
            bfs[i][j] = 0;
        }
    }
    queue<pair<int, int>>q;
    int count = 1;
    q.push({ y,x });
    bfs[y][x] = 1;
    while (q.size()) {
        int yy = q.front().first;
        int xx = q.front().second;
        q.pop();
        if (count == v.size()) 
            return 1;
        for (int i = 0; i < 4; i++) {
            int dy = yy + d[i][0];
            int dx = xx + d[i][1];
            if (dy >= 5 || dy < 0 || dx >= 5 || dx < 0)
                continue;
            if (bfs[dy][dx])
                continue;
            if (mat[dy][dx] == '*') {
                q.push({ dy,dx });
                bfs[dy][dx] = 1;
                count++;
            }
        }
    }
    return 0;
}

uint32_t getState() {
    uint32_t state = 0;
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            if (mat[i][j] == '*') {
                int idx = i * 5 + j;
                state |= (1u << idx);
            }
        }
    }
    return state;
}

void dfs(int idx, int cnt) {
    if (idx == v.size()) {
        uint32_t state = getState();
        if (st.count(state) && st[state] <= cnt) return;
        st[state] = cnt;
        if (check()) ans = min(ans, cnt);
        return;
    }
    if (cnt >= ans)
        return;
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            if (!vis[i][j]) {
                vis[i][j] = 1;
                mat[i][j] = '*';
                int dis = abs(v[idx].first - i) + abs(v[idx].second - j);
                dfs(idx + 1, cnt + dis);
                mat[i][j] = '.';
                vis[i][j] = 0;
            }
        }
    }
}

void solve() {
    dfs(0, 0);
    cout << ans;
}

void input() {
    for (int i = 0; i < 5; i++) {
        cin >> mat[i];
        for (int j = 0; j < 5; j++) {
            if (mat[i][j] == '*') {
                v.push_back({ i,j });
                mat[i][j] = '.';
            }
        }
    }
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    input();
    solve();
}

마무리

완전 탐색으로 진행한 풀이가 이해가 더 쉽고 빨랐다. 하지만 map과 비트연산을 동시에 활용해볼 수 있는 문제였어서 비트마스킹을 활용해서도 풀이를 진행해봤다..

'백준 문제풀이 > dfs' 카테고리의 다른 글

[BOJ] 24232 망가진 나무  (1) 2025.11.07
[BOJ] 23887 프린트 전달  (0) 2025.10.19
[BOJ] 14657 준오는 최종인재야!!  (0) 2025.10.05
'백준 문제풀이/dfs' 카테고리의 다른 글
  • [BOJ] 24232 망가진 나무
  • [BOJ] 23887 프린트 전달
  • [BOJ] 14657 준오는 최종인재야!!
mvg01
mvg01
지능 낮은 컴퓨터공학부 4학년의 블로그
  • mvg01
    mvg01 님의 블로그
    mvg01
  • 전체
    오늘
    어제
    • 분류 전체보기 (87)
      • 백준 문제풀이 (29)
        • bfs (13)
        • dfs (4)
        • shortest path (1)
        • implemetation (1)
        • data structure (5)
        • dynamic programming (2)
        • greedy (1)
        • brute force (0)
        • back tracking (1)
        • string (0)
        • binary search (1)
      • 드림핵 문제풀이 (42)
        • web (17)
        • reversing (6)
        • pwnable (2)
        • misc (10)
        • forensics (7)
      • 우아한테크코스 8기 백엔드 (5)
      • 정보 보안 (0)
        • WEB (0)
        • Reversing (0)
        • 시스템 해킹 (0)
        • Forensics (0)
      • 임베디드 (4)
        • NVIDIA Jetson (4)
        • raspberry pi (0)
      • AI (6)
        • Claude (3)
        • OpenAI gpt (1)
        • n8n (2)
      • 서평 (1)
  • 인기 글

  • 최근 글

  • 링크

  • hELLO· Designed By정상우.v4.10.3
mvg01
[BOJ] 1035 조각 움직이기
상단으로

티스토리툴바