반응형
리뷰
3 * 3크기의 퍼즐을 정렬된 상태로 만드는 최단 시간을 구하는 문제
https://www.acmicpc.net/problem/1525
전역 변수
- lst : 초기 퍼즐 정보를 저장할 정수형 2차 배열
- v : 퍼즐의 상태를 방문처리 하기 위한 해시맵
- dx, dy : 4방향 탐색을 위한 방향 배열
- Pos : 퍼즐의 현재 상태를 정의하기 위한 구조체, 좌표 위치 x, y와 현재 맵 정보 b, 현재까지 소요 시간 t로 구성되며 t를 기준으로 오름차순 정렬한다.
함수
1. bfs
int bfs(const Pos& start)
너비 우선 탐색을 통해 퍼즐이 정렬되기 까지 걸리는 최소 시간을 구하는 함수
- 매개변수로 초기 퍼즐 정보 start를 전달받는다.
- Pos타입의 우선순위 큐 q를 초기화 하고, start를 q에 push해준다.
- 시작 퍼즐 위치 정보를 해시맵 v의 key로 방문처리를 진행해 준다.
- 정렬이 완료된 상태의 값을 변수 target에 저장해 준다.
- q가 빌 때 까지 while루프를 수행해 주고, 매 루프마다 요소를 한개씩 꺼내어 준다.
- 현재 위치 cx, cy와 현재 맵 정보 cb, 소요시간 ct로 구조체 내 변수를 파싱해 준다.
- 기저 조건으로 cb가 target에 도달하였다면 ct를 리턴해 준다.
- 4방향 탐색을 진행하며 맵의 범위 안에 있다면 이동을 진행해 준다.
- 변수 nf에 이동하고자 하는 위치의 값을 파싱해 준다.
- 변수 nb에 이동하고자 하는 위치의 값을 빼주고, 현재 위치에 해당 값을 추가해 준다.
- 만약 nb가 방문처리 되어 있다면 continue처리해 준다.
- 방문처리 되지 않았다면 방문처리 후 q에 이동 위치와 변경된 맵, 소요 시간을 증가시켜 push해준다.
- while루프가 종료될 때 까지 기저 조건에 도달하지 못한 경우 -1을 리턴해 준다.
문제풀이
- 초기 퍼즐의 정보를 저장할 Pos타입의 변수 pos를 초기화 해준다.
- 정수형 변수 bits를 0으로 초기화 해준다, 해당 변수에 초기 맵 정보를 저장해줄 예정이다.
- 3 * 3크기의 맵 정보를 입력 받는다, 만약 0이 입력된 경우 pos에 해당 위치를 초기화 해주고 continue해준다.
- bits에 현재 좌표의 값을 10에 제곱하고 번호를 곱한 만큼의 값을 더해준다.
- 입력을 모두 받은 후 pos의 b에 bits값을 저장해 준다.
- bfs함수에 pos를 매개변수로 전달하고 리턴값을 출력해 준다.
트러블 슈팅
- 3 * 3크기 이므로 최대 2^10 - 1크기의 변수로 비트마스킹을 진행하려 했으나 2의 제곱수가 존재하여 포기했다.
- 맵을 변경하지 않은 상태에서 맵 정보를 체크하기 위해 9자리의 정수로 표현이 가능했다.
참고 사항
- 정렬된 상태를 87654321로 정의하였다, 각 자릿수를 맵 상에서 3 * i + j의 인덱스 좌표로 매핑하였다.
- 따라서 예제 1번의 초기 맵은 687524301이며, 예제 2번의 초기 맵은 5472180653이다.
- 이동할 위치에 저장된 값을 구해놓고, 현재 위치를 해당 값으로, 이동할 위치를 0으로 변경해 주었다.
- 범위가 최대 10^9 - 1이므로 방문 상태를 처리하려면 배열이 아닌 해시맵을 통해 구현해 주어야 한다.
정답 코드
#include<iostream>
#include<queue>
#include<cmath>
#include<unordered_map>
using namespace std;
int lst[3][3];
unordered_map<int, bool> v;
int dx[] = { 1, -1, 0, 0 };
int dy[] = { 0, 0, 1, -1 };
struct Pos {
int x, y, b, t;
bool operator<(const Pos& other) const {
return t > other.t;
}
};
int bfs(const Pos& start) {
priority_queue<Pos> q;
q.push(start);
v[start.b] = 1;
int target = 87654321;
while (!q.empty()) {
Pos pos = q.top(); q.pop();
int cx = pos.x, cy = pos.y, cb = pos.b, ct = pos.t;
if (cb == target) return ct;
for (int i = 0; i < 4; ++i) {
int nx = cx + dx[i], ny = cy + dy[i], nt = ct + 1;
if (0 <= nx && nx < 3 && 0 <= ny && ny < 3) {
int nf = cb / (int)pow(10, 3 * nx + ny) % 10;
int nb = cb - (int)pow(10, 3 * nx + ny) * nf + (int)pow(10, 3 * cx + cy) * nf;
if (v[nb]) continue;
v[nb] = 1;
q.push({ nx, ny, nb, nt });
}
}
}
return -1;
}
int main() {
Pos pos;
int bits = 0;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
cin >> lst[i][j];
if (!lst[i][j]) {
pos = { i, j, 0, 0 };
continue;
}
bits += pow(10, 3 * i + j) * lst[i][j];
}
}
pos.b = bits;
cout << bfs(pos);
}
728x90
반응형
'알고리즘 공부 > C++' 카테고리의 다른 글
[G4] 백준 16120번 PPAP C++ 스택, 문자열 (0) | 2025.01.13 |
---|---|
[G5] 백준 1351번 무한 수열 C++ 다이나믹 프로그래밍, 해시맵, 재귀 (0) | 2025.01.12 |
[G5] 백준 2212번 센서 C++ (0) | 2025.01.10 |
[G1] 백준 1700번 멀티탭 스케줄링 C++ 그리디 알고리즘, 해시 셋 (1) | 2025.01.09 |
[G2] 백준 2437번 저울 C++ 그리디 알고리즘 (0) | 2025.01.09 |