ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준][17837번] 새로운 게임2
    Algorithm/백준 2020. 9. 21. 23:49

    www.acmicpc.net/problem/17837

     

    17837번: 새로운 게임 2

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

    www.acmicpc.net

    문제

    재현이는 주변을 살펴보던 중 체스판과 말을 이용해서 새로운 게임을 만들기로 했다. 새로운 게임은 크기가 N×N인 체스판에서 진행되고, 사용하는 말의 개수는 K개이다. 말은 원판모양이고, 하나의 말 위에 다른 말을 올릴 수 있다. 체스판의 각 칸은 흰색, 빨간색, 파란색 중 하나로 색칠되어있다.

    게임은 체스판 위에 말 K개를 놓고 시작한다. 말은 1번부터 K번까지 번호가 매겨져 있고, 이동 방향도 미리 정해져 있다. 이동 방향은 위, 아래, 왼쪽, 오른쪽 4가지 중 하나이다.

    턴 한 번은 1번 말부터 K번 말까지 순서대로 이동시키는 것이다. 한 말이 이동할 때 위에 올려져 있는 말도 함께 이동한다. 말의 이동 방향에 있는 칸에 따라서 말의 이동이 다르며 아래와 같다. 턴이 진행되던 중에 말이 4개 이상 쌓이는 순간 게임이 종료된다.

    • A번 말이 이동하려는 칸이
      • 흰색인 경우에는 그 칸으로 이동한다. 이동하려는 칸에 말이 이미 있는 경우에는 가장 위에 A번 말을 올려놓는다.
        • A번 말의 위에 다른 말이 있는 경우에는 A번 말과 위에 있는 모든 말이 이동한다.
        • 예를 들어, A, B, C로 쌓여있고, 이동하려는 칸에 D, E가 있는 경우에는 A번 말이 이동한 후에는 D, E, A, B, C가 된다.
      • 빨간색인 경우에는 이동한 후에 A번 말과 그 위에 있는 모든 말의 쌓여있는 순서를 반대로 바꾼다.
        • A, B, C가 이동하고, 이동하려는 칸에 말이 없는 경우에는 C, B, A가 된다.
        • A, D, F, G가 이동하고, 이동하려는 칸에 말이 E, C, B로 있는 경우에는 E, C, B, G, F, D, A가 된다.
      • 파란색인 경우에는 A번 말의 이동 방향을 반대로 하고 한 칸 이동한다. 방향을 반대로 바꾼 후에 이동하려는 칸이 파란색인 경우에는 이동하지 않고 가만히 있는다.
      • 체스판을 벗어나는 경우에는 파란색과 같은 경우이다.

    입력

    첫째 줄에 체스판의 크기 N, 말의 개수 K가 주어진다. 둘째 줄부터 N개의 줄에 체스판의 정보가 주어진다. 체스판의 정보는 정수로 이루어져 있고, 각 정수는 칸의 색을 의미한다. 0은 흰색, 1은 빨간색, 2는 파란색이다.

    다음 K개의 줄에 말의 정보가 1번 말부터 순서대로 주어진다. 말의 정보는 세 개의 정수로 이루어져 있고, 순서대로 행, 열의 번호, 이동 방향이다. 행과 열의 번호는 1부터 시작하고, 이동 방향은 4보다 작거나 같은 자연수이고 1부터 순서대로 →, ←, ↑, ↓의 의미를 갖는다.

    같은 칸에 말이 두 개 이상 있는 경우는 입력으로 주어지지 않는다.

    출력

    게임이 종료되는 턴의 번호를 출력한다. 그 값이 1,000보다 크거나 절대로 게임이 종료되지 않는 경우에는 -1을 출력한다.

    제한

    • 4 ≤ N ≤ 12
    • 4 ≤ K ≤ 10

     

    풀이과정

    1. 시뮬레이션으로 접근했다. (딱히 알고리즘적으로 생각나지 않았음..!)

    2. g_chess벡터는 chess의 정보를 가진다 (현재 위치, 방향) 

     : 선언한 이유는 맵을 모두 체크하면서 체스의 순서대로 움직이는 것은 낭비이므로 바로 사용 할 수 있도록 선언함.

    3. map은 체스판의 색을 담당하는 배열이다.

    4. chessMap은 벡터의 배열로 각 위치에 체스의 갯수를 담당한다.

     : 모든 체스의 위치 중 같은 것은 4개 이상 찾는 것보다, 현 위치의 vector 사이즈를 체크 하는 것이 더 편하다고 생각함.

     

    5. 시퀀스 마다 모든 체스가 순서대로 이동한다. (g_chess에 순서대로 담겨있다.)

    6. 이동 할 체스판의 색에 맞게 동작을 취하면 된다. 내 위로 존재하는 체스는 모두 이동 시킨다.

       chessMap에 순서대로 담겨있다. index가 높은 것은 나보다 위에 있는 뜻이다.

       removeAndMove함수에서 현재 이동 할 밸류의 위치를 찾고, moveList에 넣어준다.

       moveList 포함 된 체스는 변경되는 위치로 업데이트 한다. (g_chess의 인덱스와 chessMap의 값은 매핑시켜둠)

       빨간 색일 경우 moveList를 reverse시킨다.

     

    * 파란색의 경우 방향을 바꾸고 얻은 위치는 다시 한번 범위를 벗어나는지 체크 해야 한다.

    * 매 순간순간 현재 체스의 갯수 합이 4가 넘으면 종료 시켜야 한다. (이 조건을 체크하지 않아 시간이 좀 걸렸다..)

     

     

    소스코드(c++)

    더보기
    #include <stdio.h>
    #include <vector>
    #include <algorithm>
    using namespace std;
    struct chess {
    	int x;
    	int y;
    	int dir;
    }typedef chess;
    
    int N, K;
    int map[12][12];
    vector<int> chessMap[12][12];
    int dx[4] = { 1, -1, 0, 0 };
    int dy[4] = { 0, 0, -1, 1 };
    vector<chess> g_chess;
    
    void removeAndMove(int x, int y, int val, int nx, int ny, int color) {
    	vector<int>::iterator itr = find(chessMap[y][x].begin(), chessMap[y][x].end(), val);
    	vector<int> moveList;
    	for (itr; itr != chessMap[y][x].end();) {
    		moveList.push_back(*itr);
    		itr = chessMap[y][x].erase(itr);
    	}
    
    	if (color == 1) {
    		reverse(moveList.begin(), moveList.end());
    	}
    
    	for (int i = 0; i < moveList.size(); i++) {
    		int chessId = moveList[i];
    		g_chess[chessId].x = nx;
    		g_chess[chessId].y = ny;
    		chessMap[ny][nx].push_back(chessId);
    	}
    }
    
    int calcNewDis(int d) {
    	switch (d)
    	{
    		case 0: return 1;
    		case 1: return 0;
    		case 2: return 3;
    		case 3: return 2;
    	}
    }
    
    int solution()
    {
    	int count = 0;
    	while (count <= 1000) {
    		for (int i = 0; i < N; i++) {
    			for (int j = 0; j < N; j++) {
    				if (chessMap[i][j].size() >= 4) {
    					return count;
    				}
    			}
    		}
    		
    		for (int i = 0; i < K; i++) {
    			chess &curChess = g_chess[i];
    			int nx = curChess.x + dx[curChess.dir];
    			int ny = curChess.y + dy[curChess.dir];
    			if (nx < 0 || ny < 0 || nx >= N || ny >= N || map[ny][nx] == 2) {
    				curChess.dir = calcNewDis(curChess.dir);
    				nx = curChess.x + dx[curChess.dir];
    				ny = curChess.y + dy[curChess.dir];
    				if (nx < 0 || ny < 0 || nx >= N || ny >= N || map[ny][nx] == 2) continue;
    			}
    			
    			if (map[ny][nx] == 0) {
    				removeAndMove(curChess.x, curChess.y, i, nx, ny, 0);
    			}
    			else if (map[ny][nx] == 1) {
    				removeAndMove(curChess.x, curChess.y, i, nx, ny, 1);
    			}
    			if (chessMap[ny][nx].size() >= 4) return count + 1;
    		}
    		count++;
    	}
    	return -1;
    }
    
    int main()
    {
    	scanf("%d %d",&N, &K);
    	for (int i = 0; i < N; i++) {
    		for (int j = 0; j < N; j++) {
    			scanf("%d", &map[i][j]);
    		}
    	}
    
    	for (int i = 0; i < K; i++) {
    		int x, y, d;
    		scanf("%d %d %d", &y, &x, &d);
    		chess tmp = { x - 1, y - 1, d - 1 };
    		g_chess.push_back(tmp);
    		chessMap[y - 1][x - 1].push_back(i);
    	}
    	printf("%d\n", solution());
    }

     

    결과

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

    [백준][17471번] 게리맨더링  (0) 2020.10.02
    [백준][17779번] 게리맨더링2  (0) 2020.09.24
    [백준] [19238번] 스타트 택시  (0) 2020.09.20
    [백준][19236번] 청소년 상어  (0) 2020.09.19
    [백준][9935번] 문자열 폭팔  (0) 2020.07.12

    댓글

Designed by Tistory.