https://www.acmicpc.net/problem/23288
N x M 인 지도, 오른쪽이 동쪽, 위쪽이 북쪽
지도의 좌표 표시 (r, c), r은 북쪽으로부터 떨어진 칸의 수, c는 서쪽으로부터 떨어진 칸의 수
가장 왼쪽 위에 있는 칸의 좌표가 (1, 1)이고 가장 아래에 있는 칸의 좌표가 (N, M)이다.
주사위 이동 방식(최초 주사위의 위치는 (1, 1)이고, 윗 면이 1이고, 동쪽을 바라보고 있는 상태)
1. 주사위가 이동 방향으로 한칸 굴러간다. 해당 방향에 칸이 없다면 이동 방향을 반대로 바꾸고 한칸 굴러간다.
2. 주사위가 도착한 칸(x, y)에 대한 점수 획득
3. 주사위의 아랫면에 있는 정수 A와 주사위가 있는 칸 (x, y)에 있는 정수 B를 비교해 이동 방향 결정
1) A > B인 경우 이동 방향을 90도 시계 방향으로 회전시킨다.
2) A < B인 경우 이동 방향을 90도 반시계 방향으로 회전시킨다.
3) A = B인 경우 이동 방향에 변화는 없다.
입력
N(세로 크기, 1~20), M(가로 크기, 1~20), K(이동하는 횟수, 1~1000)
NxM 크기의 2차원 배열이 주어짐
출력
각 이동에서 획득한 점수 합 출력
누적되는 점수는 해당 칸의 숫자가 동인하고 이어져 있는 칸 수의 해당 숫자곱과 같다.
우선 그래프탐색을 통해 각 칸에 따라 얻을 수 있는 점수를 만들어준다.
이후 주사위 이동 규칙에 따라 점수를 누적시켜준다.
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
struct Dice
{
int R = 0;
int C = 0;
int Dir = 3;
int Contact = 6;
int Up = 2;
int Right = 3;
};
int board[21][21];
bool check[21][21];
int point[21][21];
int N, M, K, count;
//상, 하, 좌, 우
int idx[4] = {0,0,-1,1};
int idy[4] = {-1,1,0,0};
queue<pair<int,int>>q;
Dice dice;
//가로, 세로 길이가 다름 주의
bool valid(int r, int c){ return r>=0 && r<N && c>=0 && c<M; }
//최초 point 지도를 만들기 위한 함수
void dfs(int r, int c){
if(check[r][c] == true) return;
q.push({r,c});
check[r][c] = true;
for(int i = 0;i<4;i++){
int nr = r + idy[i];
int nc = c + idx[i];
if(valid(nr,nc) == false || board[nr][nc] != board[r][c] || check[nr][nc] == true) continue;
count++;
dfs(nr, nc);
}
}
//방향 주의
void move(){
if(dice.Contact > board[dice.R][dice.C]){//시계방향 90도 회전
if(dice.Dir == 0)
dice.Dir = 3;
else if(dice.Dir == 1)
dice.Dir = 2;
else if(dice.Dir == 2)
dice.Dir = 0;
else
dice.Dir = 1;
}
else if(dice.Contact < board[dice.R][dice.C]){//반시계방향 90도 회전
if(dice.Dir == 0)
dice.Dir = 2;
else if(dice.Dir == 1)
dice.Dir = 3;
else if(dice.Dir == 2)
dice.Dir = 1;
else
dice.Dir = 0;
}
}
int solve(){
int temp;
int nr;
int nc;
if(dice.Dir == 0){//상
nr = dice.R + idy[0];
nc = dice.C + idx[0];
if(valid(nr,nc) == true){
temp = dice.Up;
dice.Up = 7-dice.Contact;
dice.Contact = temp;
dice.R--;
move();
}
else{
temp = dice.Contact;
dice.Contact = 7-dice.Up;
dice.Up = temp;
dice.Dir = 1;
dice.R++;
move();
}
}
else if(dice.Dir == 1){//하
nr = dice.R + idy[1];
nc = dice.C + idx[1];
if(valid(nr,nc) == true){
temp = dice.Contact;
dice.Contact = 7-dice.Up;
dice.Up = temp;
dice.R++;
move();
}
else{
temp = dice.Up;
dice.Up = 7-dice.Contact;
dice.Contact = temp;
dice.Dir = 0;
dice.R--;
move();
}
}
else if(dice.Dir == 2){//좌
nr = dice.R + idy[2];
nc = dice.C + idx[2];
if(valid(nr,nc) == true){
temp = dice.Contact;
dice.Contact = 7-dice.Right;
dice.Right = temp;
dice.C--;
move();
}
else{
temp = dice.Contact;
dice.Contact = dice.Right;
dice.Right = 7-temp;
dice.Dir = 3;
dice.C++;
move();
}
}
else{//우
nr = dice.R + idy[3];
nc = dice.C + idx[3];
if(valid(nr,nc) == true){
temp = dice.Contact;
dice.Contact = dice.Right;
dice.Right = 7-temp;
dice.C++;
move();
}
else{
temp = dice.Contact;
dice.Contact = 7-dice.Right;
dice.Right = temp;
dice.Dir = 2;
dice.C--;
move();
}
}
return point[dice.R][dice.C];
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
bool temp = false;
int answer = 0;
cin >> N >> M >> K;
for(int i = 0;i<N;i++){
for(int j = 0;j<M;j++)
cin >> board[i][j];
}
for(int i = 0;i<N;i++){
for(int j = 0;j<M;j++){
temp = false;
if(check[i][j]==false)
temp = true;
count = 1;
dfs(i, j);
if(temp == true){
int sum = count * board[i][j];
int S = q.size();
for(int i = 0;i<S;i++){
pair<int,int>T = q.front();
point[T.first][T.second] = sum;
q.pop();
}
}
}
}
for(int i = 0;i<K;i++)
answer += solve();
cout << answer << '\n';
return 0;
}
*느낀점
이 시뮬레이션 문제 유형은 의식의 흐름대로 풀다보니 코드가 다소 난잡한 경우가 많은 것같다.
반복되는 동작을 축약하는 과정이 필요해보인다.
그리고 이렇게 2차원을 이동하는 문제는 2차원 배열 인덱스와 방향 부분이 많이 혼동되는 부분이므로 주의가 필요하다.
'🥇Baekjoon Solutions > 삼성SW 기출' 카테고리의 다른 글
[C++] 백준 14891번: 톱니바퀴 (0) | 2022.04.28 |
---|---|
[C++] 백준 16236번: 아기 상어 (0) | 2022.04.26 |
[C++] 백준 14503번: 로봇 청소기(삼성SW기출) (0) | 2021.10.24 |
[C++] 백준 12100번: 2048 (Easy)(삼성SW기출) (0) | 2021.09.22 |
[C++] 백준 13460번: 구슬 탈출2(삼성SW기출) (0) | 2021.09.19 |
댓글