문제 링크
https://www.acmicpc.net/problem/23288
서론 : TC를 이용하면 더 빠르게 풀 수 있으니 참고하자.
◆문제 해결 및 설명◆
문제 요약
처음에 지도의 크기와 주사위의 횟수, 그리고 지도가 입력된다.
주사위를 진행방향으로 굴리고 (지도에 그려진 숫자) * (같은 숫자들이 상하좌우 연결된 갯수)를 점수에 합하고 진행 방향과 값을 (주사위 밑면과 지도에 그려진 숫자와 비교하여) 알맞게 바꾼다.
빨간색과 주황색은 구현, 파란색은 그래프를 중심으로 풀었다.
객체지향적 접근으로 일단 주사위가 무슨 정보를 필요로 하는지 생각하였다.
- 각 면의 값
- 진행 방향
- 지도위의 위치
따라서 필요한 변수를 선언과 함께 초기화해주었다.
class Dice
{
private:
enum Dir
{
top,down,left,right
};
Dir dirIs = right;
int row, col;
int bottomValue = 6;
int topValue = 5;
int downValue = 2;
int leftValue = 4;
int rihgtValue = 3;
int upsideValue = 1;
}
주사위가 행해야할 동작들은 이것이다.
- 굴리기
- 그래프 탐색으로 (같은 숫자들이 상하좌우 연결된 갯수) 구하기
- 점수 더하기
- 방향 전환하기(각 면의 값 변경하기)
이를 실행해줄 함수를 선언하였다. 코드가 길므로 선언만 보여드리겠다.
public:
void Roll();
void CalPoint();
void dfs(int r, int c);
void ChangeDir();
void NextValue();
Roll()을 통해서 진행할 수 있다면 주사위를 진행방향으로 굴리고, 불가능 하다면(OutfoBound) 방향을 바꾸고 Roll을 다시 호출하여 실행시켰다.
그 다음 CalPoint()를 통해서 (지도에 그려진 숫자) * (같은 숫자들이 상하좌우 연결된 갯수)를 점수에 합하고,
ChangeDir()과 NextValue()을 통하여 진행 방향과 값을 (주사위 밑면과 지도에 그려진 숫자와 비교하여) 알맞게 바꾼다.
◆코드 전문◆
#include <iostream>
#include <vector>
using namespace std;
int N, M, K, Point = 0, dfsDepth = 0;
vector<vector<int>> map;
vector<vector<int>> dfsVisited;
class Dice
{
private:
enum Dir
{
top,
down,
left,
right
};
Dir dirIs = right;
int row, col;
int bottomValue = 6;
int topValue = 5;
int downValue = 2;
int leftValue = 4;
int rihgtValue = 3;
int upsideValue = 1;
public:
Dice(int row, int col);
void Roll();
void ChangeDir();
void NextValue();
void CalPoint();
void dfs(int r, int c);
};
Dice::Dice(int row, int col)
{
this->row = row;
this->col = col;
}
void Dice::Roll()
{
switch (dirIs)
{
int nc;
int nr;
case right:
nc = col + 1;
if (nc >= M)
{
nc -= 1;
dirIs = left;
Roll();
return;
}
else
{
col = nc;
CalPoint();
NextValue();
ChangeDir();
}
break;
case left:
nc = col - 1;
if (nc < 0)
{
nc += 1;
dirIs = right;
Roll();
return;
}
else
{
col = nc;
CalPoint();
NextValue();
ChangeDir();
}
break;
case top:
nr = row - 1;
if (nr < 0)
{
nr += 1;
dirIs = down;
Roll();
return;
}
else
{
row = nr;
CalPoint();
NextValue();
ChangeDir();
}
break;
case down:
nr = row + 1;
if (nr >= N)
{
nr -= 1;
dirIs = top;
Roll();
return;
}
else
{
row = nr;
CalPoint();
NextValue();
ChangeDir();
}
break;
default:
break;
}
}
void Dice::ChangeDir()
{
if (bottomValue > map[row][col])
{
switch (dirIs)
{
case top:
dirIs = right;
break;
case right:
dirIs = down;
break;
case down:
dirIs = left;
break;
case left:
dirIs = top;
break;
default:
break;
}
}
else if (bottomValue < map[row][col])
{
switch (dirIs)
{
case top:
dirIs = left;
break;
case right:
dirIs = top;
break;
case down:
dirIs = right;
break;
case left:
dirIs = down;
break;
default:
break;
}
}
}
void Dice::NextValue()
{
int buf_bottomValue = bottomValue;
int buf_topValue = topValue;
int buf_downValue = downValue;
int buf_leftValue = leftValue;
int buf_rightValue = rihgtValue;
int buf_upsideValue = upsideValue;
switch (dirIs)
{
case top:
upsideValue = buf_topValue;
topValue = buf_bottomValue;
downValue = buf_upsideValue;
bottomValue = buf_downValue;
break;
case right:
bottomValue = buf_rightValue;
upsideValue = buf_leftValue;
leftValue = buf_bottomValue;
rihgtValue = buf_upsideValue;
break;
case down:
upsideValue = buf_downValue;
topValue = buf_upsideValue;
downValue = buf_bottomValue;
bottomValue = buf_topValue;
break;
case left:
bottomValue = buf_leftValue;
upsideValue = buf_rightValue;
leftValue = buf_upsideValue;
rihgtValue = buf_bottomValue;
break;
default:
break;
}
}
void Dice::CalPoint()
{
dfs(row, col);
Point += map[row][col] * dfsDepth;
dfsDepth = 0;
dfsVisited = vector<vector<int>>(N, vector<int>(M));
}
void Dice::dfs(int r, int c)
{
if (dfsVisited[r][c])
{
return;
}
dfsVisited[r][c] = 1;
int dy[]{1, -1, 0, 0};
int dx[]{0, 0, 1, -1};
for (int i = 0; i < 4; i++)
{
int ny = r + dy[i];
int nx = c + dx[i];
if (ny >= 0 && ny < N && nx >= 0 && nx < M)
{
if (map[r][c] == map[ny][nx])
{
dfs(ny, nx);
}
}
}
dfsDepth++;
return;
}
int main()
{
cin >> N >> M >> K;
map = vector<vector<int>>(N, vector<int>(M));
dfsVisited = vector<vector<int>>(N, vector<int>(M));
for (int i = 0; i < N; i++)
{
for (int j = 0; j < M; j++)
{
cin >> map[i][j];
}
}
Dice dice(0, 0);
while (K--)
{
dice.Roll();
}
cout << Point;
}
◆여담◆
친구가 이 문제를 풀때 머리 아파서 직접 주사위를 그렸단다는 소릴 들었는데, 풀고나니 그럴만 했다 라는 생각을 했다.
나도 주사위의 면의 Value값에서 오류가 났는데 찾기 되게 힘들었는데 TC에 진행상황에 따른 전개도를 제공해줘서 그냥 전게도에 값이 맞게 설정해 주었더니 정답이 되었다.