알고리즘 모음(C++)

백준 17837 - 새로운 게임2(C++) 본문

백준

백준 17837 - 새로운 게임2(C++)

공대생의 잡다한 사전 2022. 1. 16. 17:35

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

 

17837번: 새로운 게임 2

재현이는 주변을 살펴보던 중 체스판과 말을 이용해서 새로운 게임을 만들기로 했다. 새로운 게임은 크기가 N×N인 체스판에서 진행되고, 사용하는 말의 개수는 K개이다. 말은 원판모양이고, 하

www.acmicpc.net

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

문제 조건
출력 예시

까다로운 구현 문제였습니다.

게임이 멈추는 경우는 3가지입니다.

1. 턴이 1000번보다 넘게 진행되었을 경우   -> -1를 출력

2. 게임을 진행해도 끝낼수 없는 경우         -> -1를 출력

3. 블럭을 움직였을때 4개 이상의 블럭이 쌓였을 경우  -> 턴 횟수를 출력

 

3번 경우가 있기 때문에, vector를 통해서, (X , Y) 좌표에 어느 블럭이 쌓여있는지를 저장했습니다.

 

블럭이 움직이는 경우는 4가지입니다.

1. 하얀색 칸에 도달했을 경우               -> X번 블럭부터 해당 칸으로 이동한다.

ex) 1 2 3 4 5        ->       1 2 / 3 4 5       (3번을 움직일 경우)

2. 빨간색 칸에 도달했을 경우               -> X번 블럭부터 거꾸로 해당 칸으로 이동한다.

ex) 1 2 3 4 5        ->       1 2 / 5 4 3       (3번을 움직일 경우)

3. 파란색 칸에 도달했을 경우               -> 방향을 바꾼뒤, 1번 혹은 2번 경우를 실행한다.

4. 움직인 곳이 map의 범위 밖일 경우    -> 3번 경우와 같다.

 

 

1. 게임이 끝나는 경우 중 -1를 출력하는 경우

////////////// solve 함수 중 /////////////////	
    if (ans > 1000) {
		cout << "-1";
        break;
	}
/////////////////////////////////////////////
        
bool check_first() {
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= N; j++) {
			if (many_block[i][j] != first_map[i][j]) return 0;
		}
	}
	return 1;
}

ans 변수의 의미는 턴이 진행된 횟수입니다. 

턴이 1000번보다 많이 진행됐을때, -1를 출력하고 break 했습니다.

 

first_map vector는 처음 블럭의 위치를 가지고 있습니다.

현재 쌓여있는 블럭을 나타내는 many_block 과 first_map이 같은 경우 1를 return했습니다.

 

 

2. 게임이 끝나는 경우 중 턴을 출력하는 경우

bool game_finish() {
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= N; j++) {
			if (many_block[i][j].size() >= 4) return 1;
		}
	}
	return 0;
}

한 좌표에서 블럭이 4개 이상 쌓여있으면 턴을 출력합니다. 조건에 따라 해당 경우 1을 return 했습니다.

 

 

3. 블럭의 움직임 구현 - 하얀색 칸

void white_space(int x, int y, int num) {
	int x1 = block[num].row, y1 = block[num].col;
	int Size = many_block[x1][y1].size();
	int start = 0;
	for (int i = 0; i < Size; i++) {
		if (num == many_block[x1][y1][i]) {
			start = i;
			break;
		}
	}
	for (int i = start; i < Size; i++) {
		int X = many_block[x1][y1][i];
		many_block[x][y].push_back(X);
		block[X] = { x,y,block[X].way };
	}
	for (int i = start; i < Size; i++) {
		many_block[x1][y1].pop_back();
	}
}

X번 블럭 위로 모든 블럭을 (x ,y)로 옮기는 역할을 합니다.

X번 블럭이 자신의 좌표에서 몇번째에 위치하는지를 먼저 확인합니다. -> start 변수

start부터 블럭이 쌓여있는 수까지 다음 좌표로 블럭을 계속 옮겨줍니다.

블럭을 다 옮긴후, 해당 블럭들을 빼야하니 pop_back()을 해줍니다.

 

 

4. 블럭의 움직임 구현 - 빨간색

void red_space(int x, int y, int num) {
	int x1 = block[num].row, y1 = block[num].col;
	int Size = many_block[x1][y1].size();
	int start = 0;
	for (int i = 0; i < Size; i++) {
		if (num == many_block[x1][y1][i]) {
			start = i;
			break;
		}
	}
	for (int i = Size - 1; i >= start; i--) {
		int X = many_block[x1][y1][i];
		many_block[x][y].push_back(X);
		block[X] = { x,y,block[X].way };
	}
	for (int i = start; i < Size; i++) {
		many_block[x1][y1].pop_back();
	}
}

X번 블럭 위로 모든 블럭을 (x ,y)로 거꾸로 옮기는 역할을 합니다.

X번 블럭이 자신의 좌표에서 몇번째에 위치하는지를 먼저 확인합니다. -> start 변수

블럭이 쌓여있는 수부터 start까지 다음 좌표로 블럭을 계속 옮겨줍니다.

블럭을 다 옮긴후, 해당 블럭들을 빼야하니 pop_back()을 해줍니다.

 

 

문제 접근 방법

1. 입력받은 블럭의 위치를 저장한다.

2. 1번 블럭부터 K번 블럭까지 순서대로 블럭을 움직여준다.

   2-1. 블럭의 다음 좌표가 map 범위안일 경우 -> 하얀색, 빨간색, 파란색의 경우에 따라 움직여줍니다.

   2-2. 블럭의 다음 좌표가 map 범위밖일 경우 -> 파란색의 경우와 같이 해줍니다.

3. 블럭이 움직일 때마다 게임이 끝날 수 있는지를 확인합니다.(4개 이상 쌓이는가?)

4. 게임이 끝난다면 경우에 따라 답을 출력해줍니다.

 

 

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

#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, K;
int map[13][13];   // 0 - 흰색, 1 - 빨간색, 2 - 파란색
vector<int> first_map[13][13];
vector<int> many_block[13][13];
typedef struct bk {
	int row;
	int col;
	int way;
}bk;
bk block[11];
int dx[5] = { 0,0,0,-1,1 }; // 그대로, 오, 왼, 상, 하
int dy[5] = { 0,1,-1,0,0 };

int change_way(int x) {
	if (x == 1 || x == 3) return x + 1;
	else return x - 1;
}

bool game_finish() {
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= N; j++) {
			if (many_block[i][j].size() >= 4) return 1;
		}
	}
	return 0;
}

void white_space(int x, int y, int num) {
	int x1 = block[num].row, y1 = block[num].col;
	int Size = many_block[x1][y1].size();
	int start = 0;
	for (int i = 0; i < Size; i++) {
		if (num == many_block[x1][y1][i]) {
			start = i;
			break;
		}
	}
	for (int i = start; i < Size; i++) {
		int X = many_block[x1][y1][i];
		many_block[x][y].push_back(X);
		block[X] = { x,y,block[X].way };
	}
	for (int i = start; i < Size; i++) {
		many_block[x1][y1].pop_back();
	}
}

void red_space(int x, int y, int num) {
	int x1 = block[num].row, y1 = block[num].col;
	int Size = many_block[x1][y1].size();
	int start = 0;
	for (int i = 0; i < Size; i++) {
		if (num == many_block[x1][y1][i]) {
			start = i;
			break;
		}
	}
	for (int i = Size - 1; i >= start; i--) {
		int X = many_block[x1][y1][i];
		many_block[x][y].push_back(X);
		block[X] = { x,y,block[X].way };
	}
	for (int i = start; i < Size; i++) {
		many_block[x1][y1].pop_back();
	}
}

void move_block(int x) {
	int xx = block[x].row + dx[block[x].way];
	int yy = block[x].col + dy[block[x].way];
	if (xx >= 1 && xx <= N && yy >= 1 && yy <= N) {
		if (map[xx][yy] == 0) {
			white_space(xx, yy, x);
		}
		else if (map[xx][yy] == 1) {
			red_space(xx, yy, x);
		}
		else {
			block[x].way = change_way(block[x].way);
			xx = block[x].row + dx[block[x].way];
			yy = block[x].col + dy[block[x].way];
			if (xx >= 1 && xx <= N && yy >= 1 && yy <= N) {
				if (map[xx][yy] == 0) {
					white_space(xx, yy, x);
				}
				else if (map[xx][yy] == 1) {
					red_space(xx, yy, x);
				}
			}
		}
	}
	else {
		block[x].way = change_way(block[x].way);
		xx = block[x].row + dx[block[x].way];
		yy = block[x].col + dy[block[x].way];
		if (xx >= 1 && xx <= N && yy >= 1 && yy <= N) {
			if (map[xx][yy] == 0) {
				white_space(xx, yy, x);
			}
			else if (map[xx][yy] == 1) {
				red_space(xx, yy, x);
			}
		}
	}
}

bool check_first() {
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= N; j++) {
			if (many_block[i][j] != first_map[i][j]) return 0;
		}
	}
	return 1;
}

void solve() {
	int ans = 1;
	while (1) {
		if (ans > 1000) {
			cout << "-1";
			break;
		}
		if (check_first() && ans > 1) {
			cout << "-1";
			break;
		}
		for (int i = 1; i <= K; i++) {
			move_block(i);
			if (game_finish()) {
				cout << ans;
				return;
			}
		}
		ans++;
	}
}

int main()
{
	cin.tie(0);
	cout.tie(0);
	cin >> N >> K;
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= N; j++) {
			cin >> map[i][j];
		}
	}
	for (int i = 1; i <= K; i++) {
		cin >> block[i].row >> block[i].col >> block[i].way;
		many_block[block[i].row][block[i].col].push_back(i);
		first_map[block[i].row][block[i].col].push_back(i);
	}
	solve();
	return 0;
}

 

 

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

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

백준 1992 - 쿼드트리(C++)  (0) 2022.01.24
백준 17780 - 새로운 게임(C++)  (0) 2022.01.17
백준 14889 - 스타트와 링크(C++)  (0) 2022.01.11
백준 14888 - 연산자 끼워넣기(C++)  (0) 2022.01.09
백준 19237 - 어른 상어(C++)  (0) 2022.01.09