알고리즘 모음(C++)

백준 23288 - 주사위 굴리기2(C++) 본문

백준

백준 23288 - 주사위 굴리기2(C++)

공대생의 잡다한 사전 2022. 1. 9. 01:24

문제 링크입니다. https://www.acmicpc.net/problem/23288

 

23288번: 주사위 굴리기 2

크기가 N×M인 지도가 존재한다. 지도의 오른쪽은 동쪽, 위쪽은 북쪽이다. 지도의 좌표는 (r, c)로 나타내며, r는 북쪽으로부터 떨어진 칸의 개수, c는 서쪽으로부터 떨어진 칸의 개수이다. 가장 왼

www.acmicpc.net

삼성 SW 역량테스트 기출문제입니다.

주사위 굴리기 + BFS가 합쳐진 문제였습니다.

문제 조건
출력 예시

주사위를 동서남북으로 바꿀때, 값이 어떻게 변하는지를 나타냈습니다.

이를 통해서 주사위를 구리는 것을 구현할 수 있습니다.

 

1. 주사위 방향 바꾸기

int change_way_180(int x) {
	if (x == 0 || x == 2) return x + 1;
	else return x - 1;
}

int change_way_90(int x, int y) {
	if (y == 1) {
		if (x == 0) return 2;
		else if (x == 1) return 3;
		else if (x == 2) return 1;
		else return 0;
	}
	else {
		if (x == 0) return 3;
		else if (x == 1) return 2;
		else if (x == 2) return 0;
		else return 1;
	}
}

1. 반대 방향으로 움직일 경우 : 동 <-> 서남 <-> 북 임으로 값을 바꿔주면 됩니다.

2. 시계 방향으로 움직일 경우 : 동 -> 남 , 서 -> 북 , 남 -> 서 , 북 -> 동  임으로 값을 바꿔주면 됩니다.

3. 반시계 방향으로 움직일 경우 : 동 -> 북  , 서 -> 남 , 남 -> 동 , 북 -> 서 임으로 값을 바꿔주면 됩니다.

 

 

2. 주사위 이동하기

int move_dice(int x) {
	int next_dice[7];
	int point = 0;
	int xx = dice_location.first + dx[way];
	int yy = dice_location.second + dy[way];
	if (xx >= 1 && xx <= N && yy >= 1 && yy <= M) {
		for (int i = 0; i < 7; i++) {
			next_dice[i] = dice[dice_move[way][i]];
		}
		for (int i = 0; i < 7; i++) {
			dice[i] = next_dice[i];
		}
		if (dice[6] > map[xx][yy]) {
			way = change_way_90(way, 1);
		}
		else if (dice[6] < map[xx][yy]) {
			way = change_way_90(way, -1);
		}
		point = map[xx][yy] * check[xx][yy];
		dice_location = { xx,yy };
	}
	else{
		way = change_way_180(way);
		xx = dice_location.first + dx[way];
		yy = dice_location.second + dy[way];
		for (int i = 0; i < 7; i++) {
			next_dice[i] = dice[dice_move[way][i]];
		}
		for (int i = 0; i < 7; i++) {
			dice[i] = next_dice[i];
		}
		if (dice[6] > map[xx][yy]) {
			way = change_way_90(way, 1);
		}
		else if (dice[6] < map[xx][yy]) {
			way = change_way_90(way, -1);
		}
		point = map[xx][yy] * check[xx][yy];
		dice_location = { xx,yy };
	}
	return point;
}

주사위가 이동할 수 있는 경우는 2가지입니다.

1. 이동한 곳이 좌표를 벗어나지 않을때 -> 해당 좌표로 이동한다.

2. 이동한 곳이 좌표를 벗어날때 -> 이동 방향을 180도 바꾼뒤, 다시 이동한다.

다음 좌표로 이동했다면, 다음 이동 방향을 정해야합니다. A와 B의 값을 통해 방향을 정하니 이를 구현합니다.

 

한번 이동할 때마다 얻을 수 있는 점수는 map[xx][yy]의 값 * 해당 좌표에서 이동할 수 있는 좌표의 수 임으로 이를 더해줍니다.

 

 

3. (X,Y)에서 이동할 수 있는 값 구하기

void get_point(int x, int y, int cnt) {
	queue<pair<int, int>> q, location;
	int many = 1;
	q.push(make_pair(x, y));
	location.push(make_pair(x, y));
	check[x][y] = 1;
	while (!q.empty()) {
		int x1 = q.front().first;
		int y1 = q.front().second;
		q.pop();
		for (int i = 0; i < 4; i++) {
			int xx = x1 + dx[i];
			int yy = y1 + dy[i];
			if (xx >= 1 && xx <= N && yy >= 1 && yy <= M) {
				if (check[xx][yy] == 0 && map[xx][yy] == cnt) {
					location.push(make_pair(xx, yy));
					q.push(make_pair(xx, yy));
					check[xx][yy] = 1;
					many++;
				}
			}
		}
	}
	while (!location.empty()) {
		check[location.front().first][location.front().second] = many;
		location.pop();
	}
}

(X , Y) 좌표에서 이동할 수 있는 좌표의 수를 구하는 코드입니다.

BFS 탐색을 통해서 몇개의 좌표를 이동할 수 있는지를 찾은뒤, 이동한 좌표에 해당 값을 전부 넣었습니다.

 

 

문제 접근 방법

1. (X , Y)에서 이동할 수 있는 좌표의 값을 먼저 구해줍니다.

2. 동쪽으로 이동하는 것을 시작으로 주사위를 K번 이동해줍니다.

 

 

자세한 것은 코드를 참고해주세요.

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <cmath>
#include <cstring>

using namespace std;

int N, M, K;
int dice_move[4][7] = { // 0번째 배열은 안쓰는 칸
	{ 0,4,2,1,6,5,3 },  // 동
	{ 0,3,2,6,1,5,4 },  // 서
	{ 0,2,6,3,4,1,5 },  // 남
	{ 0,5,1,3,4,6,2 }   // 북
	
};
int map[21][21];
int check[21][21];
pair<int, int> dice_location = { 1,1 };
int dice[7] = { 0,1,2,3,4,5,6 };  //주사위 아랫면의 값은 6번(0번에서 시작)
int dx[4] = { 0,0,1,-1 }; //동서남북
int dy[4] = { 1,-1,0,0 };
int way = 0; // 시작할 때 이동방향 = 동쪽

int change_way_180(int x) {
	if (x == 0 || x == 2) return x + 1;
	else return x - 1;
}

int change_way_90(int x, int y) {
	if (y == 1) {
		if (x == 0) return 2;
		else if (x == 1) return 3;
		else if (x == 2) return 1;
		else return 0;
	}
	else {
		if (x == 0) return 3;
		else if (x == 1) return 2;
		else if (x == 2) return 0;
		else return 1;
	}
}

int move_dice(int x) {
	int next_dice[7];
	int point = 0;
	int xx = dice_location.first + dx[way];
	int yy = dice_location.second + dy[way];
	if (xx >= 1 && xx <= N && yy >= 1 && yy <= M) {
		for (int i = 0; i < 7; i++) {
			next_dice[i] = dice[dice_move[way][i]];
		}
		for (int i = 0; i < 7; i++) {
			dice[i] = next_dice[i];
		}
		if (dice[6] > map[xx][yy]) {
			way = change_way_90(way, 1);
		}
		else if (dice[6] < map[xx][yy]) {
			way = change_way_90(way, -1);
		}
		point = map[xx][yy] * check[xx][yy];
		dice_location = { xx,yy };
	}
	else{
		way = change_way_180(way);
		xx = dice_location.first + dx[way];
		yy = dice_location.second + dy[way];
		for (int i = 0; i < 7; i++) {
			next_dice[i] = dice[dice_move[way][i]];
		}
		for (int i = 0; i < 7; i++) {
			dice[i] = next_dice[i];
		}
		if (dice[6] > map[xx][yy]) {
			way = change_way_90(way, 1);
		}
		else if (dice[6] < map[xx][yy]) {
			way = change_way_90(way, -1);
		}
		point = map[xx][yy] * check[xx][yy];
		dice_location = { xx,yy };
	}
	return point;
}

void get_point(int x, int y, int cnt) {
	queue<pair<int, int>> q, location;
	int many = 1;
	q.push(make_pair(x, y));
	location.push(make_pair(x, y));
	check[x][y] = 1;
	while (!q.empty()) {
		int x1 = q.front().first;
		int y1 = q.front().second;
		q.pop();
		for (int i = 0; i < 4; i++) {
			int xx = x1 + dx[i];
			int yy = y1 + dy[i];
			if (xx >= 1 && xx <= N && yy >= 1 && yy <= M) {
				if (check[xx][yy] == 0 && map[xx][yy] == cnt) {
					location.push(make_pair(xx, yy));
					q.push(make_pair(xx, yy));
					check[xx][yy] = 1;
					many++;
				}
			}
		}
	}
	while (!location.empty()) {
		check[location.front().first][location.front().second] = many;
		location.pop();
	}
}

void solve() {
	int ans = 0;
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= M; j++) {
			if (check[i][j] == 0) {
				get_point(i, j, map[i][j]);
			}
		}
	}
	for (int i = 0; i < K; i++) {
		ans += move_dice(way);
	}
	cout << ans;
}

int main()
{
	cin.tie(0);
	cout.tie(0);
	cin >> N >> M >> K;
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= M; j++) {
			cin >> map[i][j];
		}
	}
	solve();
	return 0;
}

 

 

질문 및 조언 댓글 남겨주세요!

'백준' 카테고리의 다른 글

백준 14888 - 연산자 끼워넣기(C++)  (0) 2022.01.09
백준 19237 - 어른 상어(C++)  (0) 2022.01.09
백준 14891 - 톱니바퀴(C++)  (0) 2022.01.07
백준 21608 - 상어 초등학교(C++)  (0) 2022.01.06
백준 3190 - 뱀(C++)  (0) 2022.01.05