본문 바로가기
Programming/BOJ

#1525 퍼즐

by 작은별하나 2022. 9. 1.
반응형

우리는 4x4짜리 슬라이딩 퍼즐은 자주 갈지고 놀게 됩니다.

 

슬라이딩 퍼즐은 아래의 그림과 같이 생겼는데요.  비어있는 칸이 있고, 이 칸의 주변 상하좌우에서 숫자를 옮길 수 있습니다.

 

슬라이딩 퍼즐

이번 문제는 4x4 슬라이딩 퍼즐이 아니고 3x3 슬라이딩 퍼즐입니다.

슬라이딩 퍼즐이 주어지면, 가장 빠르게 맞출 때 최소의 이동횟수를 푸는 것입니다.

불가능한 경우도 생깁니다.  이건 숫자가 있어야할 곳과 비어있는 칸의 위치로 원래 판단할 수 있습니다.  하지만, 그것을 이용해서 프로그램하지는 않았습니다.

 

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

 

1525번: 퍼즐

세 줄에 걸쳐서 표에 채워져 있는 아홉 개의 수가 주어진다. 한 줄에 세 개의 수가 주어지며, 빈 칸은 0으로 나타낸다.

www.acmicpc.net

 

저는 너비 우선 탐색(BFS)를 이용하여 문제를 풀었습니다.  왜 다익스트라나 A* 알고리즘을 쓰지 않았는가 궁금할 수 있겠죠.  일단 이동 경로의 간선의 가중치가 모두 1이면 다익스트라 알고리즘이나 너비 우선 탐색 알고리즘은 동일합니다.  A* 알고리즘을 적용하면 더 빠르게 문제를 풀 수는 있습니다.  하지만 모든 경우의 수를 따져보면 그다지 효율적이지 않고, 예측 경로의 이동수가 실제 움직여야 하는 거리보다 훨씬 짧게 구성해야 하므로 결국 탐색해야 하는 경우의 수가 많아집니다.  A* 알고리즘은 예측 경로가 실제와 비슷할 수록 효율적이니까요.

 

일단 퍼즐의 빈칸을 0으로 나머지는 숫자로 표현해서 그래프 노드를 표현했습니다.

1   3
4 2 5
7 8 6

위와 같은 경우에는 103425786 으로 표현했습니다.  최대 자릿수는 9자리수이므로 정수형 변수로 표현할 수 있습니다.

대신 방문했음을 표시해주기 위해서는 해시맵을 이용했습니다.  메모리 공간을 할당하기에는 너무 많으니까요.

 

그래서 작성한 소스입니다.  소스는 참고용으로만 봐주세요.

//-----------------------------------------------------------------------------------
//    baekjoon #1525 - Puzzle
//        - by Aubrey Choi
//        - created at 2019-11-27
//-----------------------------------------------------------------------------------
#include <stdio.h>
#include <unordered_map>
#include <queue>

int main()
{
    int goal=123456780, s=0, t, i, j, r, c, rc, nr, nc, nrc, ns, v[100];
    const int d[][2]={0,1, 1,0, 0,-1, -1,0};
    std::unordered_map<int,int> map;
    std::queue<int> q;
    for(i=0;i<9;i++) { scanf("%d",&t); s=s*10+t; }
    q.push(s); map[s]=0;
    while(!q.empty())
    {
        s=q.front(); q.pop();
        for(i=0,t=100000000;i<9;i++,t/=10) v[i]=(s/t)%10;
        if(s==goal) break;
        for(rc=0;rc<9;rc++) if(!v[rc]) break;
        r=rc/3, c=rc%3;
        for(i=0;i<4;i++)
        {
            nr=r+d[i][0], nc=c+d[i][1], nrc=nr*3+nc;
            if(nr<0||nr>=3||nc<0||nc>=3) continue;
            for(ns=0,j=0;j<9;j++) ns=ns*10+((j==rc)?v[nrc]:(j==nrc)?0:v[j]);
            if(map.find(ns)!=map.end()) continue;
            q.push(ns); map[ns]=map[s]+1;
        }
    }
    printf("%d\n", s==goal?map[s]:-1);
}
728x90

'Programming > BOJ' 카테고리의 다른 글

[C/C++] 백준 #1541 잃어버린 괄호(탐욕 알고리즘)  (0) 2022.09.02
#1535 안녕  (0) 2022.09.02
#1521 랜덤 소트(dynamic programming)  (0) 2022.08.31
#1520 내리막 길  (0) 2022.08.29
#1517 버블 소트  (0) 2022.08.23

댓글