문제
https://www.acmicpc.net/problem/1525
구상
빈칸을 움직여서 배열의 상태가 원하는 상태로 나오게끔 하는데, 이때의 최소 이동 횟수를 구하는 문제였다. 최소 이동 횟수를 구하는 것이다 보니 bfs를 이용하는 문제라는 건 인지했지만, 원하는 상태로 바꾸는 데에 있어서 빈칸을 언제까지 움직여볼 것인가에 대한 고민이 들었다. 단순하게 방문했는지의 여부를 판단하기에는 빈칸을 움직이는 순서에 따라서 상황이 다양하게 바뀔 수 있었다. 그래서 그 이전에 해당 상황에 도달한 적이 없다면, 큐에 넣는 방식을 택했다.
*map의 find(key) 결과값이 map.end()값과 같다면, 원소가 없다는 뜻이다.
*만일 원소가 있다면, map<Key, T>::iterator 를 반환하고, iterator는 -> 연산자를 사용하여 std::pair<const Key, T> 타입의 값을 참조할 수 있다. ex) auto it = myMap.find(key); string key = it -> first; int value = it -> second
처음에는 3*3 2중 벡터를 사용했었는데, 이동횟수를 배열 상태와 map으로 매핑하기가 불편해서 배열 크기도 정해져있겠다 3*3 배열로 되어있는 퍼즐의 상태를 string으로 변환해서 사용했다. 빈칸을 움직일 때에는 string에서의 빈칸 인덱스를 사용하여 배열 상에서의 빈칸의 위치(x, y좌표)를 알아낸 다음 어디로 이동할 수 있는지 판단하고, 이동할 수 있는 곳의 배열상 위치를 string 상의 인덱스로 변환하여 swapping 해주었다.
풀이 + 코드
#include<iostream>
#include<vector>
#include<algorithm>
#include<map>
#include<queue>
#define MAX 101
#define INF 987654321
#define endl "\n"
using namespace std;
// 1525 퍼즐
string answer = "123456780";
string now = "";
map<string, int> mov; // 상태와 해당 상태에 도달하기 위한 횟수
queue<string> q;
vector<pair<int, int>> dxy = { {1, 0}, {0, 1}, {-1, 0}, {0, -1} };
int res = -1;
void solution() { // bfs
while (!q.empty()) {
string curr = q.front();
q.pop();
if (curr == answer) {
res = mov[curr];
return;
}
// 0 위치 찾기
int idx = curr.find('0');
int x = idx % 3;
int y = idx / 3;
for (int i = 0; i < 4; i++) {
int n_x = x + dxy[i].first;
int n_y = y + dxy[i].second;
int n_idx = n_y * 3 + n_x;
if (n_x < 0 || n_x >= 3 || n_y < 0 || n_y >= 3) continue; // 경계에서 벗어났을 때
string next = curr;
swap(next[idx], next[n_idx]); // 원소 두개 바꾸기
if (mov.find(next) == mov.end()) { // 방문 여부를 확인하는게 아니라, 이전에 나왔던 상태인지의 여부를 판단하는 것.
q.push(next);
mov[next] = mov[curr] + 1;
}
}
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
// 입력
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
string a; cin >> a;
now.append(a);
}
}
q.push(now);
mov[now] = 0;
// 로직
solution();
// 출력
cout << res;
return 0;
}
'알고리즘 > 문제풀이' 카테고리의 다른 글
[코드트리/C++] 해시함수 (Hashing) (1) | 2024.09.05 |
---|---|
[코드트리/C++] 캣타워 돌리기 (Simulation) (0) | 2024.09.05 |
[백준/C++] #4195 친구 네트워크 (Union Find) (1) | 2024.08.28 |
[백준/C++] #1696 중앙값 구하기 (자료구조) (0) | 2024.08.27 |
[백준/C++] #24229 모두싸인 출근길 (Greedy) (0) | 2024.08.26 |