[백준/BOJ] 백준 23288번 : 주사위 굴리기 2

2021. 11. 23. 12:11알고리즘 문제풀이

https://www.acmicpc.net/problem/23288

 

23288번: 주사위 굴리기 2

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

www.acmicpc.net

각 칸에서 몇 점을 얻을 수 있는지 계산을 해 놓고, 주사위를 움직이는 방법으로 문제를 해결했다.

 

코드

#include <iostream>
#include <vector>
#include <utility>
#include <queue>
using namespace std;

int n, m, k;
int board[20][20];
int result = 0;
pair<int, int> point = make_pair(0, 0);
int dir = 2;
int dxdy[4][2] = { {0,-1},{-1,0},{0,1},{1,0} };

int u_side = 1; //위
int d_side = 6; //아래
int l_side = 4; //왼쪽
int r_side = 3; //오른쪽
int f_side = 5; //앞쪽
int b_side = 2; //뒤쪽

vector<vector<int>> discovered(20, vector<int>(20, 0));
vector<vector<int>> score(20, vector<int>(20));

void MakeScore(pair<int, int> start)
{
	vector<pair<int, int>> check;
	queue<pair<int, int>> q;
	int cnt = 0;

	discovered[start.first][start.second] = 1;
	check.push_back(start);
	q.push(start);
	cnt++;

	while (!q.empty())
	{
		pair<int, int> here = q.front();
		q.pop();

		for (int d = 0; d < 4; d++)
		{
			pair<int, int> there = make_pair(here.first + dxdy[d][0], here.second + dxdy[d][1]);

			if (there.first >= 0 && there.first < n && there.second >= 0 && there.second < m && board[here.first][here.second] == board[there.first][there.second] && discovered[there.first][there.second] == 0)
			{
				discovered[there.first][there.second] = 1;
				check.push_back(there);
				q.push(there);
				cnt++;
			}
		}
	}

	for (int i = 0; i < check.size(); i++)
	{
		score[check[i].first][check[i].second] = cnt * board[start.first][start.second];
	}
}

//dir방향으로 움직인다
void Move()
{
	//이동하는 방향이 범위를 벗어날때
	if (point.first + dxdy[dir][0] < 0 || point.first + dxdy[dir][0] >= n || point.second + dxdy[dir][1] < 0 || point.second + dxdy[dir][1] >= m)
	{
		if (dir == 0)
			dir = 2;
		else if (dir == 1)
			dir = 3;
		else if (dir == 2)
			dir = 0;
		else if (dir == 3)
			dir = 1;
	}

	//왼쪽
	if (dir == 0)
	{
		int temp = d_side;

		d_side = l_side;
		l_side = u_side;
		u_side = r_side;
		r_side = temp;

		point = make_pair(point.first + dxdy[dir][0], point.second + dxdy[dir][1]);
	}

	//위쪽
	else if (dir == 1)
	{
		int temp = d_side;

		d_side = b_side;
		b_side = u_side;
		u_side = f_side;
		f_side = temp;

		point = make_pair(point.first + dxdy[dir][0], point.second + dxdy[dir][1]);
	}

	//오른쪽
	else if (dir == 2)
	{
		int temp = d_side;

		d_side = r_side;
		r_side = u_side;
		u_side = l_side;
		l_side = temp;

		point = make_pair(point.first + dxdy[dir][0], point.second + dxdy[dir][1]);
	}

	//아래쪽
	else
	{
		int temp = d_side;

		d_side = f_side;
		f_side = u_side;
		u_side = b_side;
		b_side = temp;

		point = make_pair(point.first + dxdy[dir][0], point.second + dxdy[dir][1]);
	}
}

int main()
{
	cin.tie(NULL);
	ios_base::sync_with_stdio(false);

	cin >> n >> m >> k;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
		{
			int input;
			cin >> input;

			board[i][j] = input;
		}

	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
		{
			if (discovered[i][j] == 0)
			{
				MakeScore(make_pair(i, j)); //각 칸에서 몇점을 얻을 수 있는지 계산
			}
		}

	for (int i = 0; i < k; i++)
	{
		Move(); //이동
		result += score[point.first][point.second]; //점수획득

		//이동방향 결정
		int a = d_side;
		int b = board[point.first][point.second];

		if (a > b)
		{
			dir++;
			if (dir == 4)
				dir = 0;
		}
		else if (a < b)
		{
			dir--;
			if (dir == -1)
				dir = 3;
		}
	}

	cout << result;

	return 0;
}