Notice
Recent Posts
Recent Comments
Link
넘치게 채우기
[BOJ] 12906 - 새로운 하노이 탑 본문
반응형
https://www.acmicpc.net/problem/12906
BOJ - 새로운 하노이 탑
문제 유형: BFS, 해시, 문자열 처리
문제 난이도: Gold III
시간 제한: 3초
메모리 제한: 512MB
문제
오늘은 새로운 하노이 탑 게임을 해보려고 한다. 이 게임의 규칙은 다음과 같다.
- 막대는 총 세 가지 종류가 있다. 막대 A, 막대 B, 막대 C
- 게임이 시작될 때, 각각의 막대에는 0개 또는 그 이상의 원판이 놓여져 있다.
- 모든 원판의 크기는 같으며, 원판의 종류도 A, B, C로 세 가지가 있다. 원판은 원판 A, 원판 B, 원판 C와 같이 표현한다.
- 한 번 움직이는 것은 한 막대의 가장 위에 있는 원판을 다른 막대의 가장 위로 옮기는 것이다.
- 게임의 목표는 막대 A에는 원판 A만, 막대 B는 원판 B만, 막대 C는 원판 C만 놓여져 있어야 한다.
- 되도록 최소로 움직여야 한다.
막대 A, 막대 B, 막대 C에 놓여져 있는 원판의 상태가 주어졌을 때, 게임의 목표를 달성하는데 필요한 움직임의 최소 횟수를 구하는 프로그램을 작성하시오.
입력
첫째 줄에 막대 A에 놓여져 있는 원판의 개수와 막대 A의 상태, 둘째 줄에 막대 B에 놓여져 있는 원판의 개수와 막대 B의 상태, 셋째 줄에 막대 C에 놓여져 있는 원판의 개수와 막대 C의 상태가 주어진다. 막대의 상태는 밑에 있는 원판부터 주어진다.
각 막대의 상태는 A, B, C로만 이루어진 문자열이며, 모든 막대에 놓여져 있는 원판 개수의 합은 1보다 크거나 같고, 10보다 작거나 같다.
출력
게임의 목표를 달성하는데 필요한 움직임의 최소 횟수를 출력한다.
풀이
mp[상태문자열] = 최소 횟수로 해시맵을 구성한다.
상태문자열은 A상태 + '|' + B상태 + '|' + C상태로 한다.
매번 bfs를 하며 A -> B, A -> C, B -> A, B -> C, C -> A, C -> B의 총 6가지 선택지를 택한다.
목표 상태문자열은 "AAAAA..AA|BBBBB...BB|CCCCC...CC"의 꼴이다. 즉, "A*|B*|C*"의 꼴이다.
목표 상태문자열에 도달하면 bfs를 멈추면 된다.
코드
C++
#include <bits/stdc++.h>
using namespace std;
string romans = "ABC";
string ans;
bool check(string &conc) {
int curr = 0;
for (int i = 0; i < conc.size(); i++) {
if (conc[i] == '|') {
curr++;
continue;
}
if (conc[i] != romans[curr]) {
return false;
}
}
return true;
}
void cut(string &conc, string &a, string &b, string &c) {
int i = 0;
while (i < conc.size() && conc[i] != '|') {
a += conc[i];
i++;
}
i++;
while (i < conc.size() && conc[i] != '|') {
b += conc[i];
i++;
}
i++;
while (i < conc.size() && conc[i] != '|') {
c += conc[i];
i++;
}
}
int main(int argc, char *argv[]) {
ios::sync_with_stdio(0);
cin.tie(0);
string a = "", b = "", c = "";
int al, bl, cl;
unordered_map<string, int> dist;
cin >> al;
if (al > 0) cin >> a;
cin >> bl;
if (bl > 0) cin >> b;
cin >> cl;
if (cl > 0) cin >> c;
string state = a + '|' + b + '|' + c;
dist[state] = 0;
queue<string> q;
q.emplace(state);
while (!q.empty()) {
string curr = q.front();
q.pop();
if (check(curr)) {
ans = curr;
break;
}
string A, B, C;
cut(curr, A, B, C);
if (!A.empty()) {
char disk = A.back();
string poppedA = A;
poppedA.pop_back();
{
string nextB = B;
nextB.push_back(disk);
string newState = poppedA + '|' + nextB + '|' + C;
if (dist.find(newState) == dist.end()) {
dist[newState] = dist[curr] + 1;
q.push(newState);
}
}
{
string nextC = C;
nextC.push_back(disk);
string newState = poppedA + '|' + B + '|' + nextC;
if (dist.find(newState) == dist.end()) {
dist[newState] = dist[curr] + 1;
q.push(newState);
}
}
}
if (!B.empty()) {
char disk = B.back();
string poppedB = B;
poppedB.pop_back();
{
string nextA = A;
nextA.push_back(disk);
string newState = nextA + '|' + poppedB + '|' + C;
if (dist.find(newState) == dist.end()) {
dist[newState] = dist[curr] + 1;
q.push(newState);
}
}
{
string nextC = C;
nextC.push_back(disk);
string newState = A + '|' + poppedB + '|' + nextC;
if (dist.find(newState) == dist.end()) {
dist[newState] = dist[curr] + 1;
q.push(newState);
}
}
}
if (!C.empty()) {
char disk = C.back();
string poppedC = C;
poppedC.pop_back();
{
string nextA = A;
nextA.push_back(disk);
string newState = nextA + '|' + B + '|' + poppedC;
if (dist.find(newState) == dist.end()) {
dist[newState] = dist[curr] + 1;
q.push(newState);
}
}
{
string nextB = B;
nextB.push_back(disk);
string newState = A + '|' + nextB + '|' + poppedC;
if (dist.find(newState) == dist.end()) {
dist[newState] = dist[curr] + 1;
q.push(newState);
}
}
}
}
cout << dist[ans] << "\n";
return 0;
}반응형
'PS > BOJ' 카테고리의 다른 글
| [BOJ] 4563 - 피타고라스의 복수 (0) | 2025.09.15 |
|---|---|
| [BOJ] 30704 - 정사각형 연결 (0) | 2025.09.14 |
| [BOJ] 15488 - 나이트가 체스판을 벗어나지 않을 확률 (0) | 2025.09.12 |
| [BOJ] 3780 - 네트워크 연결 (0) | 2025.09.11 |
| [BOJ] 17841 - UNIST는 무엇의 약자일까? (0) | 2025.09.10 |