728x90
0. [c++] 백준 13460 - 구슬 탈출 2 |
https://www.acmicpc.net/problem/13460
1. 풀이 |
오래간만에 백준 알고리즘 문제를 풀어보았다.
일반적인 BFS 방식으로 최단 시도 횟수로 빨간 공을 구멍에 넣을 수 있는 횟수를 계산하는 문제이다.
- 아이디어
1) board class 구현 및 상하좌우 이동에 대해 구현
2) board 구현 중 bool 방식으로 위치에 대한 정보를 저장 (비교 방식 최적화)
3) fstream를 통해 Text File을 활용한 반복적인 검증 구현
4) assert를 활용해 구현한 Logic 이상 유무 판단 자동화
- 경험한 함정 요소
1) 10회를 넘는 탐색의 경우 -1을 반환
2) 빨간 공과 파란 공을 동시에 넣는 경우 -1을 반환
2. 소스코드 |
#include<vector>
#include<fstream>
#include<iostream>
#include<string>
#include<cassert>
#include<queue>
namespace ans {
class Board
{
public:
Board(const int& height, const int& width, const std::vector<std::vector<char>>& array);
~Board() = default;
int CalcBestWay();
void Move();
void MoveR();
void MoveL();
void MoveU();
void MoveD();
void Reset();
private:
int mWidth;
int mHeight;
std::vector<std::vector<bool>> mArray;
int mPosCurRed[2];
int mPosCurBlue[2];
int mPosStartRed[2];
int mPosStartBlue[2];
int mPosGoal[2];
int mCache[10][10][10][10];
int mBestCnt;
std::queue<std::pair<std::pair<int, int>, std::pair<int, int>>> mQueue;
};
Board::Board(const int& height, const int& width, const std::vector<std::vector<char>>& array)
: mHeight(height)
, mWidth(width)
, mBestCnt(-1)
{
mArray.resize(mHeight, std::vector<bool>(mWidth));
for (int y = 0; y < mHeight; ++y)
{
for (int x = 0; x < mWidth; ++x)
{
for (int y2 = 0; y2 < mHeight; ++y2)
for (int x2 = 0; x2 < mWidth; ++x2)
mCache[y][x][y2][x2] = -1;
if (array[y][x] == '#')
{
mArray[y][x] = false;
continue;
}
else if (array[y][x] == 'R')
{
mPosCurRed[1] = y;
mPosCurRed[0] = x;
mPosStartRed[1] = y;
mPosStartRed[0] = x;
}
else if (array[y][x] == 'B')
{
mPosCurBlue[1] = y;
mPosCurBlue[0] = x;
mPosStartBlue[1] = y;
mPosStartBlue[0] = x;
}
else if (array[y][x] == 'O')
{
mPosGoal[1] = y;
mPosGoal[0] = x;
}
mArray[y][x] = true;
}
}
mCache[mPosCurRed[1]][mPosCurRed[0]][mPosCurBlue[1]][mPosCurBlue[0]] = 0;
mQueue.push({ {mPosCurRed[1], mPosCurRed[0]}, {mPosCurBlue[1], mPosCurBlue[0]} });
}
int Board::CalcBestWay()
{
Move();
if (mBestCnt > 10)
return -1;
return mBestCnt;
}
void Board::Move()
{
int posRed[2];
int posBlue[2];
while (!mQueue.empty()) {
posRed[1] = mQueue.front().first.first;
posRed[0] = mQueue.front().first.second;
posBlue[1] = mQueue.front().second.first;
posBlue[0] = mQueue.front().second.second;
mQueue.pop();
mPosCurRed[1] = posRed[1];
mPosCurRed[0] = posRed[0];
mPosCurBlue[1] = posBlue[1];
mPosCurBlue[0] = posBlue[0];
MoveR();
mPosCurRed[1] = posRed[1];
mPosCurRed[0] = posRed[0];
mPosCurBlue[1] = posBlue[1];
mPosCurBlue[0] = posBlue[0];
MoveL();
mPosCurRed[1] = posRed[1];
mPosCurRed[0] = posRed[0];
mPosCurBlue[1] = posBlue[1];
mPosCurBlue[0] = posBlue[0];
MoveU();
mPosCurRed[1] = posRed[1];
mPosCurRed[0] = posRed[0];
mPosCurBlue[1] = posBlue[1];
mPosCurBlue[0] = posBlue[0];
MoveD();
if (mBestCnt != -1)
return;
}
}
void Board::MoveR()
{
int moveCount = mCache[mPosCurRed[1]][mPosCurRed[0]][mPosCurBlue[1]][mPosCurBlue[0]];
bool posFlag = mPosCurRed[0] < mPosCurBlue[0]; // [. . R B] or [. . B R]
bool redFall = false;
bool blueFall = false;
for (int x = mPosCurRed[0] + 1; x < mWidth; ++x)
{
if (mArray[mPosCurRed[1]][x])
mPosCurRed[0] = x;
else
break;
if (mPosGoal[1] == mPosCurRed[1] && mPosGoal[0] == mPosCurRed[0])
redFall = true;
}
for (int x = mPosCurBlue[0] + 1; x < mWidth; ++x)
{
if (mArray[mPosCurBlue[1]][x])
mPosCurBlue[0] = x;
else
break;
if (mPosGoal[1] == mPosCurBlue[1] && mPosGoal[0] == mPosCurBlue[0])
blueFall = true;
}
if (mPosCurRed[0] == mPosCurBlue[0] && mPosCurRed[1] == mPosCurBlue[1])
{
if (posFlag)
--mPosCurRed[0];
else
--mPosCurBlue[0];
}
if (redFall && !blueFall)
{
mBestCnt = moveCount + 1;
}
if ((mCache[mPosCurRed[1]][mPosCurRed[0]][mPosCurBlue[1]][mPosCurBlue[0]] == -1 || mCache[mPosCurRed[1]][mPosCurRed[0]][mPosCurBlue[1]][mPosCurBlue[0]] > moveCount + 1) && !redFall && !blueFall)
{
mCache[mPosCurRed[1]][mPosCurRed[0]][mPosCurBlue[1]][mPosCurBlue[0]] = moveCount + 1;
mQueue.push({ {mPosCurRed[1], mPosCurRed[0]}, {mPosCurBlue[1], mPosCurBlue[0]} });
}
}
void Board::MoveL()
{
int moveCount = mCache[mPosCurRed[1]][mPosCurRed[0]][mPosCurBlue[1]][mPosCurBlue[0]];
bool posFlag = mPosCurRed[0] < mPosCurBlue[0]; // [. . R B] or [. . B R]
bool redFall = false;
bool blueFall = false;
for (int x = mPosCurRed[0] - 1; x > 0; --x)
{
if (mArray[mPosCurRed[1]][x])
mPosCurRed[0] = x;
else
break;
if (mPosGoal[1] == mPosCurRed[1] && mPosGoal[0] == mPosCurRed[0])
redFall = true;
}
for (int x = mPosCurBlue[0] - 1; x > 0; --x)
{
if (mArray[mPosCurBlue[1]][x])
mPosCurBlue[0] = x;
else
break;
if (mPosGoal[1] == mPosCurBlue[1] && mPosGoal[0] == mPosCurBlue[0])
blueFall = true;
}
if (mPosCurRed[0] == mPosCurBlue[0] && mPosCurRed[1] == mPosCurBlue[1])
{
if (posFlag)
++mPosCurBlue[0];
else
++mPosCurRed[0];
}
if (redFall && !blueFall)
{
mBestCnt = moveCount + 1;
}
if ((mCache[mPosCurRed[1]][mPosCurRed[0]][mPosCurBlue[1]][mPosCurBlue[0]] == -1 || mCache[mPosCurRed[1]][mPosCurRed[0]][mPosCurBlue[1]][mPosCurBlue[0]] > moveCount + 1) && !redFall && !blueFall)
{
mCache[mPosCurRed[1]][mPosCurRed[0]][mPosCurBlue[1]][mPosCurBlue[0]] = moveCount + 1;
mQueue.push({ {mPosCurRed[1], mPosCurRed[0]}, {mPosCurBlue[1], mPosCurBlue[0]} });
}
}
void Board::MoveU()
{
int moveCount = mCache[mPosCurRed[1]][mPosCurRed[0]][mPosCurBlue[1]][mPosCurBlue[0]];
bool posFlag = mPosCurRed[1] < mPosCurBlue[1]; // [. . R B] or [. . B R]
bool redFall = false;
bool blueFall = false;
for (int y = mPosCurRed[1] + 1; y < mHeight; ++y)
{
if (mArray[y][mPosCurRed[0]])
mPosCurRed[1] = y;
else
break;
if (mPosGoal[1] == mPosCurRed[1] && mPosGoal[0] == mPosCurRed[0])
redFall = true;
}
for (int y = mPosCurBlue[1] + 1; y < mHeight; ++y)
{
if (mArray[y][mPosCurBlue[0]])
mPosCurBlue[1] = y;
else
break;
if (mPosGoal[1] == mPosCurBlue[1] && mPosGoal[0] == mPosCurBlue[0])
blueFall = true;
}
if (mPosCurRed[0] == mPosCurBlue[0] && mPosCurRed[1] == mPosCurBlue[1])
{
if (posFlag)
--mPosCurRed[1];
else
--mPosCurBlue[1];
}
if (redFall && !blueFall)
{
mBestCnt = moveCount + 1;
}
if ((mCache[mPosCurRed[1]][mPosCurRed[0]][mPosCurBlue[1]][mPosCurBlue[0]] == -1 || mCache[mPosCurRed[1]][mPosCurRed[0]][mPosCurBlue[1]][mPosCurBlue[0]] > moveCount + 1) && !redFall && !blueFall)
{
mCache[mPosCurRed[1]][mPosCurRed[0]][mPosCurBlue[1]][mPosCurBlue[0]] = moveCount + 1;
mQueue.push({ {mPosCurRed[1], mPosCurRed[0]}, {mPosCurBlue[1], mPosCurBlue[0]} });
}
}
void Board::MoveD()
{
int moveCount = mCache[mPosCurRed[1]][mPosCurRed[0]][mPosCurBlue[1]][mPosCurBlue[0]];
bool posFlag = mPosCurRed[1] < mPosCurBlue[1]; // [. . R B] or [. . B R]
bool redFall = false;
bool blueFall = false;
for (int y = mPosCurRed[1] - 1; y > 0; --y)
{
if (mArray[y][mPosCurRed[0]])
mPosCurRed[1] = y;
else
break;
if (mPosGoal[1] == mPosCurRed[1] && mPosGoal[0] == mPosCurRed[0])
redFall = true;
}
for (int y = mPosCurBlue[1] - 1; y > 0; --y)
{
if (mArray[y][mPosCurBlue[0]])
mPosCurBlue[1] = y;
else
break;
if (mPosGoal[1] == mPosCurBlue[1] && mPosGoal[0] == mPosCurBlue[0])
blueFall = true;
}
if (mPosCurRed[0] == mPosCurBlue[0] && mPosCurRed[1] == mPosCurBlue[1])
{
if (posFlag)
++mPosCurBlue[1];
else
++mPosCurRed[1];
}
if (redFall && !blueFall)
{
mBestCnt = moveCount + 1;
}
if ((mCache[mPosCurRed[1]][mPosCurRed[0]][mPosCurBlue[1]][mPosCurBlue[0]] == -1 || mCache[mPosCurRed[1]][mPosCurRed[0]][mPosCurBlue[1]][mPosCurBlue[0]] > moveCount + 1) && !redFall && !blueFall)
{
mCache[mPosCurRed[1]][mPosCurRed[0]][mPosCurBlue[1]][mPosCurBlue[0]] = moveCount + 1;
mQueue.push({ {mPosCurRed[1], mPosCurRed[0]}, {mPosCurBlue[1], mPosCurBlue[0]} });
}
}
void Board::Reset()
{
mPosCurBlue[1] = mPosStartBlue[1];
mPosCurBlue[0] = mPosStartBlue[0];
mPosCurRed[1] = mPosStartRed[1];
mPosCurRed[0] = mPosStartRed[0];
}
}
void test(const std::string& fileName)
{
int height, width, answer;
std::vector<std::vector<char>> array;
std::ifstream filePtr("input" + fileName + ".txt");
std::string temp;
std::getline(filePtr, temp, ' ');
height = std::stoi(temp);
std::getline(filePtr, temp);
width = std::stoi(temp);
array.resize(height, std::vector<char>(width));
int y = 0;
while (std::getline(filePtr, temp))
{
for (int x = 0; x < width; ++x)
{
array[y][x] = temp[x];
}
++y;
}
filePtr.close();
filePtr.open("output" + fileName + ".txt");
std::getline(filePtr, temp);
answer = std::stoi(temp);
filePtr.close();
ans::Board* board = new ans::Board(height, width, array);
std::cout << board->CalcBestWay() << std::endl;
//assert(answer == board->CalcBestWay());
delete board;
}
void answer()
{
int height, width;
std::cin >> height >> width;
std::vector<std::vector<char>> array;
array.resize(height, std::vector<char>(width));
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
std::cin >> array[y][x];
}
}
ans::Board* board = new ans::Board(height, width, array);
std::cout << board->CalcBestWay() << std::endl;
delete board;
}
int main()
{
//test("1");
//test("2");
//test("3");
//test("4");
//test("5");
//test("6");
//test("7");
answer();
return 0;
}
https://github.com/kyun1016/BOJ/blob/main/BOJ/13460/main.cpp
3. 참고 |
질문이나 지적 있으시면 댓글로 남겨주세요~
도움 되셨으면 하트 꾹!
'<백준> > DFS와 BFS' 카테고리의 다른 글
[C++] 백준 2206 - 벽 부수고 이동하기(BFS) (0) | 2020.03.03 |
---|---|
[C++] 백준 1697 - 숨바꼭질(BFS) (0) | 2020.03.03 |
[C++] 백준 1012 - 유기농 배추(DFS) (0) | 2020.03.03 |